Remix.run Logo
kccqzy 5 days ago

> people’s birthdays changing when they move timezones

That's because the developers use datetimes (aka timestamps) to store a single date. Just pick an arbitrary epoch date (such as January 1, 1900 as used by Excel, or my favorite January 1, 1600 since 1600 is a multiple of 400 making leap year calculations even simpler) and store the number of days elapsed since then. The rules involving leap years are much much simpler than rules involving timezones and timezone databases. The translation from/to this representation to a broken-down y/m/d takes only ~50 lines of code anyways.

Of course if you don't need to do arithmetic on dates, just store three numbers, year, month, and day.

SoftTalker 5 days ago | parent | next [-]

No, don't do that. Use a date datatype (not date/time). You aren't the first person to ever need to handle dates without times/timezones in a computer program. Use what your database/language/libraries already have to support that.

tadfisher 5 days ago | parent | next [-]

Specifically, a "local date", codified as LocalDate in every date library worth a damn, except for Javascript which chose "PlainDate" just to be different.

PaulHoule 5 days ago | parent | prev [-]

Well, for hardcore chronology Julian dates are what you do.

https://en.wikipedia.org/wiki/Julian_day

which are the moral equivalent of Unix timestamps with a different offset and multiplier. These work OK for human history but will break if you go far enough into the past or the future because uncertainty in the earth's rotation adds up over time.

If you don't care about timezones timezones may still care about you, if you want to minimize trouble it makes sense to properly use timezone-aware Zulu (GMT) dates for everything if you can.

In certain cases you might be doing data analysis or building an operational database for throttling access to an API or something and you know there are 16-bits worth of days, hours, 5-minute periods or something it can make sense to work relative to your own epoch.

5 days ago | parent [-]
[deleted]
happytoexplain 5 days ago | parent | prev | next [-]

In my humble opinion, this is not good advice unless you demonstrably need it for query performance or something. It is very easy for the logic layer to accidentally mess that up, either in reading or, worse, in writing back.

In this case, I'd suggest storing what you mean (the user wasn't born 9,487 days after Jan 1 1970. They were born Dec 23, 1995.)

Storing the literal units (and ONLY the relevant units), as the parent has, is robust and logically+semantically correct (they could add a translation layer for UX so the user doesn't have to be particular, but that's beside the point). Whether you use a string or a struct or some date-only type is moot, as long as you're literally storing the year, month, and day, and only those three things. You can ephemerally convert it to your platform's date type if you need to.

pavel_lishin 5 days ago | parent | prev | next [-]

> The translation from/to this representation to a broken-down y/m/d takes only ~50 lines of code anyways.

Didn't the article explicitly tell us not to write our own date parsing library?

kccqzy 4 days ago | parent [-]

I disagree with that. And furthermore it's not parsing. It's converting between a single integer and a tuple of three integers.

habibur 5 days ago | parent | prev [-]

> or my favorite January 1, 1600 since 1600 is a multiple of 400

You need to deal with 1600 and 2000 being leap year.

While 1700, 1800, 1900 not being a leap year.

I limit dates from 1900 to 2100. All !year%4 = leap year.

Especially when you try to convert int_date to y,m,d things get tricky.

kccqzy 4 days ago | parent | next [-]

That's exactly why I propose a multiple of 400, not a multiple of 100. The proleptic Gregorian cycle is a 400-year cycle. There are 97 leap years in it. What's tricky about it? Just take a look at my code: https://github.com/kccqzy/smartcal/blob/9cfddf7e85c2c65aa6de...

oneshtein 4 days ago | parent [-]

Why not just make a map of dates to days since 0001-01-01 in a plain text, then compress it at build time? We are not constrained by memory anymore.

Just use simple database as source of truth with all days passed since a start of human history (e.g. 6000 years ago) with labels such as "this day 12345678 was known as day XXXX-xx-xx in those regions, also known as YYYY-yy-yy in those regions, also known as ZZZZZ in this specific region". It's not a hard task to automatically compress such database into a compact representation.

jerf 5 days ago | parent | prev [-]

"Years are not leap years, unless % 4, unless % 100, unless % 400."

It's a wacky rule for sure.

2000 was fun. Everyone knows about "unless % 4", but there was also an interesting and very vocal set of people who knew about the "unless % 100" but somehow knew that without knowing about the "unless % 400" part. A very specific level of knowledge.