2020-10-22
Use UNIX milliseconds
I'm making an app with chat, so time actually matters. Most advice online boils down to "pick a format." Cool, thanks. I wrote this so I can link it instead of re-explaining it in a PR.
This is not ISO-8601 fanfic. It is me being annoyed in a structured way.
Store a UTC instant. UNIX milliseconds, or a DateTimeOffset with an explicit offset. Render local, with an explicit timezone. Never pretend a culture-specific string round-trips.
The links, for when a comment wants one. RFC 3339 is the internet profile, 2012-10-03T12:13:00Z. ISO 8601 is the broader standard, and a lot of APIs say ISO when they mean the RFC. POSIX time counts seconds from 1970-01-01T00:00:00Z, and the usual encoding ignores leap seconds. In .NET, DateTimeOffset is an instant plus an offset. A plain DateTime can be UTC, local, or unspecified, and mixing those is the historical footgun. Microsoft wrote it down. Ticks are 100 ns since year 1. Finer than a chat message needs. Patrick McKenzie's Falsehoods programmers believe about time is the list of edges that kill "just parse the string." The civil rules live in the IANA time zone database. .NET's timezone overview is the API side.
A totally ordered id can sort a chat without anyone agreeing on a clock. You still want an order a person can read, and you still want a way to reconcile two copies. A timestamp, with a plan for collisions, is the hammer.
Same instant, different strings. Seconds and milliseconds mostly left off. The opinions are mine.
| DateTime code | Description | My opinion |
|---|---|---|
| 2012-10-03T12:13:00Z | UTC time friendly | |
| 10-03-12 12:13PM | US/UK short AM/PM | Stupid, because counting 12 + 12 only makes sense when using |
| 10-03-12 12:13 | US/UK short 24H | Internaly sencible, internationally stupid |
| 10-03-2012 12:13PM | US/UK long AM/PM | see above |
| 03-10-12 12:13 | Short international | What I grew up using, but it's confusing |
| 03-10-2012 12:13 | Long international | The most sencible day-to-day format |
| 2012-10-03 12:13 | Sortable long international | Very useful for sorting |
| 2012-40-3 12:13 | year-week-weekday international | Very useful for class schedules |
| 2012-40-4 12:13 | year-week-weekday US | Who thought it was a good idea to start the week on Sunday? |
| 201210031213 | sortable character safe | Great for document naming or a timestamp on a database-row |
| 100320121213 | non-sortable character safe US | NEVER use this |
| 1349266380 | UNIX time seconds | Somewhat useful |
| 1349259180000 | UNIX time milliseconds | THE best way to use date and time, (see bellow) |
You might be confused by the "snowflaking" of the US in all of this, but it has it's reasons, mostly the unwillingness to risk confusion among it's citizens. However the US Military does use the the UTC time,
Other calendars are in use. This list is not complete, and it is eurocentric on purpose.
| Date | Decription |
|---|---|
| 5773-Tishri-18 | Hebrew |
| 1433-Dhu I-Qa'da-18 | Islamic |
| 1391-Mehr-13 | Persian |
| 1934-Asvina-12 | Indian Civil |
| Dragon-Dog-18 | Chinese variant 1 (not actually used) |
| 4710-8-18 | Chinese variant 2 (China actually use Gregorian) |
there are scores upon scores of others, some only used by tribes in micronesia or in the himalayas, (that there's probably a conversion for anyway, because developers love a challange, or some social anthropologist needs it in their research
I will not denegrade the non-gregorian calanders, and they are useful for those who share them, but I don't think I'll be using Dragon-dog-18, (though if I were, I would have to have some logic to assume it's the closest Dragon in the last 12 years)
Timezones, for storage: ignore them. Store a universal instant and convert on the way out. The video I send people is Tom Scott, The Problem with Time & Timezones.
The computer counts in milliseconds. .NET also has ticks, which are much smaller, and I do not need them here.
- Persist an unambiguous instant.
- Convert for display with an explicit timezone.
TimeZoneInfo, Noda Time, whatever you will actually maintain. - A locale string is a projection. It is not the key.