You are browsing as a guest. Sign up (or log in) to start making projects!

libspacetime

  • 15 Devlogs
  • 60 Total hours

> This is being migrated to macondo.\n A C library for date and time functions on other planets. Initially, it was just going to be the proposed Darian calendar for Martian timekeeping, but I *think* the same person who made it, also proposed calendars for Jupiter. So in case that happens, this is "spacetime".

Open comments for this post

8h 21m 26s logged

again idk if I will be doing sd instead of macondo but anyways, been doing documentation :) I also fixed ammarstime and did bindings to other langs.

0
0
5
Open comments for this post

9h 34m 1s logged

Again, in case I switch back from Macondo. More fighting with leap years - I’ll have to use AI for help. In the meantime I created a marsdate program, and did wcsfmarstime (analogous to wcsftime). I also created some initial Rust bindings :)

0
0
4
Open comments for this post

18h 39m 41s logged

Devlog now in case I switch from Macondo to Stardance. In the event that I need to, I will edit this with more details. Basically, I managed to work on strfmarstime, strpmarstime, ammarstime, and I’ve been drilling testcases.

0
0
5
Open comments for this post

1h 50m 44s logged

strfmarstime testing - week numbers

Nothing crazy to report for the current testsuite and implementation verification I’ve been doing. Basically same thing as I did before I took a break for strpmarstime.

For some formats, it will literally print anything (if it’s invalid), which appears to be normal in Glibc, so it’s normal to me.

Some locale work too on AM/PM formatting and time formatting - some do “AM”, some do “am”, Spain does “a.m.”.

The big thing is:

Week Numbers

Okay, so there are three different definitions of week numbers:

  • %U: The first day of week 1 is on Sunday. Range 00 (because sometimes in January we don’t get to Sunday for a few days), up until 53 (sometimes we actually get 53 weeks due to day placement.)

  • %V: ISO 8601, which has week 1 as the first week with at least 4 days in the new year. Range 01 to 53. (Week 0 would be represented by 52, in my testing)

  • %W: The first day of week 1 is on Monday.

But, here is the key thing about the Darian calendar: Each month resets the week. This is actually one of the things about the Gregorian Calendar some people don’t like-how the # of the day is on inconsistent weekdays.

The Darian Calendar has a neat 28 days for each month, so with 7 days a week, this isn’t a problem. And since each week is guaranteed to have four days, we can just take the number of days and divide by 7. For %W, shift by 1, because Monday (Lunae) is not the first day of the week.

However.. every 6th month is the end of a season, and it has 27 days. So we need to, in our calculations, which must go based off the nth day of the year, make sure we reset, otherwise we will lose our day alignment (because again, the week resets). So we need to realign every 167 days, and also check how many seasons passed and use that to get the amount of prior weeks we are skipping when we have modulated.

As for the leap day: It divides perfectly by 7 and 167, so it gets its own if statement case (otherwise it would read “97”).

Experience

I knew this would be weird to figure out, and challenging, but I actually had a lot of fun doing it. It kept my brain working, I stayed energetic, and I managed to have fun, which is the most important thing!

So after my long Pomodoro break, I’ll verify %W (since %U and %V are thee same), and then %w, %x, %X, %y and %Y and that will be it, since for an initial ship I don’t plan to do timezones.

0
0
4
Open comments for this post

1h 21m 21s logged

strpmarstime - basic implementation complete

Using musl as a reference, I’ve completed an.. implementation, of strpmarstime. Yesterday I must’ve placed my energy wrong because I just wasn’t super motivated and didn’t do as much coding.

Anyway:

strpmarstime is the inverse of strfmarstime, taking a date-time formatted string and given its format, entering those values into a mars_tm struct.

Everything made sense, mostly. There are still some areas of code I need to comment and reread to make sure I understand what is going on. But after strfmarstime, it isn’t too crazy.

As usual, it does the things for string parsing, like str++ to move to the rest of the string’s characters, then it parses by item.

In order to find values, I think that the calculations sort of estimate the character location of the number range, and then we import it.

Challenges

nl_langinfo

Once again, I found myself in a situation where musl can lookup strings to match values like day and month names via numerical item addresses with nl_langinfo, but I cannot (as this is not a “standard” item index). Musl is able to use this item address to iterate through the list of potential matches, which is easy to do in common goto routines.

For me, I had to basically make a pointer to an array of char* (so I had char**, once I figured it out), that was the “iteration_array”. Depending on the format, it would check the array for the match. The main confusing thing was really just the pointers. Spent about 10 minutes fighting with compiler errors until I figured it out with the help of stackoverflow and Google’s AI.

By the way, using nl_langinfo_l, which I did in strfmarstime, does not exist in locale.h by default on macOS, it’s in xlocale.h, so I made a small configure define this morning to take care of that.

The vague formats

There are several ways of determining what # week of year we are in. One format says it’s the week with at least four days, and starts indexing at like, 1 I think? And then there are a few others? I can’t remember off the top of my head.

Because there are no clear answers, I (and musl) have left these formats as “parse only”.

This really impacts week number formats, which, I guess makes sense, because if you only have that, who knows what year you are in, and how many days are in the first full “week”, however you define that.

Timezones

Skipped for now, as I have yet to take care of this, and I think some proposed timekeeping systems actually don’t do the standard one-hour intervals.. I need to look into it.

Future

Welp, it’s off to testing and verification. Yay!

0
0
3
Open comments for this post

1h 45m 53s logged

strpmarstime

I took a break from validating strfmarstime because.. well I needed it. So I started doing the function that does the opposite, takes a string, parses into into a mars_tm structure.

I am taking the same approach as musl, and enjoying myself, as in, because musl is able to lookup string matches by locale (because there is a fixed offset for dates), but I can’t, I have to manually search. But instead of copy pasting code I’m trying to setup a pointer to an array to check in a common code routine.

And now I’m getting memory issues. Yay!

0
0
5
Open comments for this post

1h 35m 58s logged

strfmarstime testing and verification - date time format locales

The %c format specifier checks the system locale for how to format the date and time.

Of course, it’s a good idea to test this. It took me a while.. unfortunately I don’t have a way of checking in test configuration if one of the formats is installed on the host system (see https://en.wikipedia.org/wiki/List_of_date_formats_by_country). I also don’t really have a nice way (as far as I know) to set test environment variables.

So what I ended on was in the test setup, just passing the LC_ALL environment variable. But this was broken for some reason?

Ah, it turns out that my logic in strfmarstime to get the locale was incorrect. For some reason,

setlocale(LC_ALL, NULL); 

does not work, and you have to use “”. My guess is that NULL goes to system default, and “” will read from environment variables.

Yay!

While Day-Month-Year format is straight forward, the few countries that use Year-Month-Day are driving me insane, like Hungary, because their formats have like, dots in them, and I’m not seeing much consistency across the other country’s formats that also have Year-Month-Day formatting.

I’ll come back to it later. It’s actually broken anyway, because my week number representations are still wrong.

0
0
7
Open comments for this post

1h 31m 15s logged

strfmarstime - ~80% complete

After about 6 hrs total, the strfmarstime function is complete, using musl as a reference, except:

  • %E (era based format)
  • %k (hour as a decimal, but including padding 0s, probably this will be a quick fix
  • %O (modifier symbols?)
  • %P (lowercase version of “am” and “pm” - need to find a good way to run tolower on a const char*)
  • All week numbering formats, because there are different standards on when the week “starts” and “how many weeks we are into the year” (e.g. first 4 days of year, vs. whether week starts on Sunday vs. Monday)
  • %z, %Z (Timezones, not implemented yet)

This was quite the grind, having strftime docs open on one screen, musl’s implementation on another, and trying to go through each format while documenting and understanding how the formatting is being processed, one by one.

I also did some slight restructuring: the __mars_tm_to_secs function exists. It is basically what mkmarstime did. I would have it not subtract by epoch, but it was causing tests to fail. Technically the strftime docs say that %s, which uses it, calls the function anyways, so it may be pointless but whatever.

Oh, speaking of %s: That is seconds since the Unix epoch. Who knows how useful that will be when this calendar implementation starts at MSD 0 (like, 1873). Also, it’s martian seconds instead of Earth seconds.

Fun shoutout to “%%”, “%t”, and “%n”, which required nothing, just setting the length of the item to “1” and returning the actual formatting character. Lol.

Welp, now it’s time to test and drill this function into oblivion.

0
0
3
Open comments for this post

3h 45m 50s logged

strfmarstime progress

I think it is warranted, otherwise I will forget later. This is part 1 of many on the journey to the strfmarstime function - which returns a formatted string of a broken down mars time structure.

This was my first time ever recreating a string formatting function - especially in C, so I learned some things along the way.

Basing off of musl

After some attempts, it became pretty clear that, although string formatting functions may seem easy, when you need to support width and padding specifiers, things get complicated.

Since I had to learn this, I decided to save time by basically recreating musl’s strftime implementation side by side. I would comment and give details on what is happening so I learned how it worked while also getting the result I need to, without just blatantly copying and pasting without giving credit.

This took about an hour since some of the variable names in musl’s implementation are like, ‘l’, ‘f’, and I had to keep it straight. I actually am writing this devlog after I spent 30+ minutes debugging some stack smashing that was happening, as a result of me putting in the wrong variable for string length into memcpy.

How it works

Basically, strftime/strfmarstime will first collect information needed for each format specifier, like if there is a character requesting padding. Then it will do each item at a time, with the given padding and width.

Here’s a fun thing I learned: There is a lot of “format++”. But format is a char*. How does that make sense?

Well, format++ actually is basically the same as doing .substring(1, format.length()) in other languages. I guess it makes sense if you think about a list of characters, and you are progressing to the next character. (Like a “cdr” of a “cons” box in functional programming).

So that helped.

Locales, locales

I wanted to come back to this later, especially because I will eventually need translations. But the %c specifier actually refers to the system locale’s date and time format. This required some hacking that came around the time I was stuck with that stack smashing. So seriously, I was stuck.

musl has it easy, it can tell by its own thread what the locale is. Here, we need to initialize locales (setlocale), and then make a locale_t object we can use with newlocale. Then we free it at the end.

Where I am now

Since the locale’s DT formatting is really just a shorthand for other specifiers, it returns “-” in its place. But as I continue forward, it will work.

1
0
22
Open comments for this post

55m 28s logged

libspacetime - preparing for localization

Nothing really crazy, but I ran gettextize, looked at as much docs as I could (the website is unreachable at the moment), and other project examples to create a basic localization setup. This will allow for localization of day and month names.

0
0
6
Open comments for this post

2h 43m 53s logged

Darian Calendar C Library: ammarstime

Probably the hurdle that will be the second hardest part of the entire libspacetime library is ammarstime. It is the same as the C stdlib’s “gmtime”, which, from a timestamp, returns a broken down time structure (struct tm) of the date/time info of that timestamp (the human readable info like day, month, year, etc.)

This is actually difficult. Seconds just count up, and you have to go backwards. You can try to divide by the amount of seconds in a year, but what about leap years?

Honestly, the math is too weird, even for me. Some parts make sense, but the rest, eh…

I referred to musl’s “secs_to_tm” function for how it did the calculations. This is what mostly guided my work, with a few pieces of calculation and numbers help from Google AI search results.

I didn’t write a test suite for this function, because I think it will be easier to do once I knock down what will be the hardest kinds of functions: *string manipulation *(e.g. strftime)

But now that I have a way to convert seconds to a mars_tm struct, it should make everything else somewhat easier. Hopefully.

0
0
2
Open comments for this post

4h 6m 40s logged

AI vs Debugging

I added some tests for Y2038, before, and after, because, of course, that could be an issue. It turned out that Darian timestamps on non-leap years (even-numbered years) were incorrect. But they were correct in leap years.

So… what gives?

Manual Looking

I thought it could be the result of the calendar epoch being incorrect (it did end up being slightly incorrect) - but I tried using other dates on non-leap years, and couldn’t find a consistent offset that all the dates were off by.

This was.. really weird. I also tried setting the year to calculate the year before - no dice.

Taking out the AI

Eventually, I decided, “screw it”, so I took GPT-5 mini and asked it to try to figure out what was happening.

Spoiler alert: It did eventually figure everything out.. but it was.. quite the process to watch it do so.

It detected that the sols-passed-at-the-start-of-month table was actually missing the value for the 8th month. Of course, adjusting this caused tests to fail, so I was hesitant to trust it. It also suggested subtracting 1 from the day count when multiplying by 86400 seconds per day. This was bogus.

Asking it to make a diff

I asked it to make a .patch or a .diff I could apply - and it didn’t work. Missing headers or invalid patch data, whatever it was, it can’t generate a .patch file. Which is kind of hilarious.

It also didn’t look back at my codebase when I applied some of it’s suggestions, so it would be making patches that refer to deleted lines that didn’t exist anymore. Could just be a skill issue.

Figure it out, man

I told it to figure out what was wrong. It spent the next ~16 mins, making a “debug mkmarstime” script, and a bunch of other small scripts like “probe_unix”, “probe_y2038” - in some cases, it was just going around in a circle - making changes that only resulted in the same prior status. I thought it was hallucinating at first, especially with the compiler errors it got. Eventually I’ll look back at the thread and it’s thinking, because like, in some ways, it was stupid, but in some ways it was smart.

I don’t know if the method to debug everything was the most efficient - but it eventually worked. Probably trying to fix the epoch, and also fix the leap years, and also fix the month - all at the same time - overwhelmed it, and my guess is there was no confidence in itself.

I’m talking too much about the AI here for code I didn’t do in a dev log. But anyway, it brute forced tested leap year handling, (it also mentioned “leap seconds” which I’m not dealing with.. so I’m not sure what the heck it’s doing), but eventually all the testcases did past.

Some helpful tidbits

It also did suggest using llround to fix some precision issues, like sometimes conversions being off by 1 second. This is actually not a terrible idea, and I may make a build-time config option for this. Since it was successful, I also asked it to import all its scripts in a test suite - which it wasn’t going anywhere for, so I decided to stop wasting energy and stop it there. Eventually I may come back to it.

Overall thoughts

So it spent at 187K tokens - and even though it did seem to go nowhere, it eventually kind of.. worked? And mkmarstime behaves properly now. I was worried the AI would just try to focus on “solution that solves testcases” instead of “solution that does actual behavior”, but the resulting diff is justified (I even had it check that the output produced was the same in its loop vs closed form intercalation).

Vibe coding, no. But vibe debugging? Well, maybe there is something to be said about it..

0
0
5
Open comments for this post

1h 44m 59s logged

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.

0
0
1
Open comments for this post

23m 8s logged

Earth Timekeeping to Mars Timekeeping Conversions

Because I’m going out to see family today - might as well get something done. I was going to add “mktime” but I realized that I’ve done Mars to Earth but not vice versa. Besides, I need an “epoch” to start time from.

Technically, I already had done this with mars_time(), I just needed to do it with any timestamp. I did “0” (January 1, 1970, midnight) locally to verify, then chose the Mariner 9 enter orbit as a testcase.

I will note, Wikipedia shows MSD (Mars Sol Date) but also Mars Julian Sol. I wonder if I’ll have to do that later.

I also will probably need to organize my tests/Makefile.am for further testcases. It will grow once I start adding time tests and not just MSD.

0
0
3
Open comments for this post

1h 17m 19s logged

libspacetime - creating a testsuite

But first, pre-stardance talk

I’ve known the Darian Calendar existed, and my goal is to spend my time over the summer to try to make it as close to system level support as possible. This includes trying to get it at kernel-level - which is another project.

Anyways, libspacetime is basically time.h but for other planets. I want it to be portable and work on as many systems as possible. For this reason I setup a GNU Autotools project (autoconf, automake, that fun stuff).

Now, the Darian calendar is not standard, but C date and time functions are. Also, timekeeping is actually complicated. So I’m kind of.. mimicking the standards, and I may not get there in terms of implementation for a while, but I try my best.

Using some sites:

And after fighting with type versions, I eventually got a current unix time, represented in Martian seconds, in a way that you can get to the current Mars Sol Date (MSD).

Uh.. I’m not a mathematician. How does the timekeeping and conversions work, I honestly don’t know off hand. This will prove to continue being a challenge… especially because like, “ok, so what is our “epoch” for mars? Still Jan 1 1970 on Earth? But the existing proposed calendar conversions use this date instead?” - lots of fun in the future.

Okay, basically pre stardance was just mars_time and the initial project.

Creating the testsuite

For test runners, there are options - TAP, DejaGNU, etc. But this isn’t Meson where you can setup test targets.

Autotest is kind of weird (that seems to be the general consensus). If you are testing executable programs, it’s great, because you can get a fixed output. But at the base level, it’s really just a bunch of shell scripts.

So in test “setup”, I want to compile my “tests”. But a user building the library may not have libspacetime headers or library installed, so we need to not only build a C target (which in itself is weird, the GNU Autotools docs for test suites doesn’t suggest this as far as I know), but we need to link against the library built in the src folder of the project and also include its headers. Kinda janky.

The lack of useful documentation examples is what I spent a lot of time on. There is also the thing with atlocal, which I think is like.. empty? But docs suggest it should be generated?

package.m4 files exist now, which I did a great job filling out now that I look back at it -_-

when it comes to actual test checks (testsuite.at), apparently it compares output, not status code.. so I have to like, verbatim tell “I expect this output”. So there goes printing out the status of the current times I am testing.

Also it is so specific, like I can’t use a newline character in the printf in the test executable.

The print is useful because a round conversion from Earth -> Martian -> Earth results in a one earth second loss. I don’t know if it’s because of floating point precision or because of the time it takes to execute the conversion from the processor.

Ideally, the application can ask the kernel for the time and it uses its own clocks - which can use a counter chip, and using the amount of increases per a set of time, can figure out how long a “cycle” is and keep time that way. That was sort of the goal of my kernel “spacetime” support, but I wanted it to show up in lsclocks, and after all clocksource is like, a hardware abstraction, not an actual clock. Idealy a clocksource could just have a lower multiplier, but the kernel still uses the best clocksource which certainly won’t be the martian one.

Anyways, use janky tools (Autotest framework), get janky results. Cheers to more date and time functions and tests.

0
0
2

Delete project?

Are you sure you want to permanently delete this project? This action cannot be undone.

All devlogs, followers, and associated data will be removed.

Followers

Loading…