The j-date Datetime Format (JDTF)

v0.9999, last updated 99x09hbnx AKA
❧ this page was opened AKA

introduction

the timestamps at the top right of it’s are:

(.beat time slaps, but is only for communicating time, not date; i absolutely think there should be an ISO 8601 extension for YYYY-MM-DD@BBB[.BBB], but that’s a discussion for another...time.)

all three are UTC (Coordinated Universal Time), so there’s no fussing with timezones, nor daylight saving time: it’s the same worldwide.

rationale

like ISO 8601 timestamps and unlike Unix timestamps, j-dates refer unambiguously to a specific point in time, but in nine characters versus 8601’s twenty-ish. like Unix timestamps, j-dates can trivially be stored as 64-bit ints (j-date-int), but can also be trivially converted to an even more human-readable form (j-date-oic).

specification

j-dates are subdivided into three parts; all zero-padded, zero-indexed base 36:

  1. the first three digits: years elapsed in the Holocene calendar
  2. the next two digits: days elapsed in said year
  3. the final four digits: deciseconds elapsed in said day

zero-padding was chosen to simplify sorting (standard ASCII collation does the job) and chunking (always 3, 2, 4), and to give the dates a uniform, easily identifiable appearance.

(there’s little to be saved by discarding these benefits for variable widths: over 97% of the years use three digits, and those that don’t will nearly never be used; 90% of the days use both of their digits; and 95% of the deciseconds use all four of theirs.)

zero-indexing was chosen for uniformity between the fields: 000000000 is zero seconds elapsed of zero days elapsed of zero years elapsed.

(cf. ISO 8601 with its rather silly mixture of zero-indexing for all time fields and one-indexing for all date fields.)

base 36 was chosen for compactness without the baggage of higher bases: case sensitivity and, beyond that, non-alphanumeric characters. j-date’s base 36 is represented conventionally: [0-9a-z], i.e. after 9 comes a (10), b (11), and so on until z (35). all alphabetic digits MUST be lowercase, though implementations SHOULD accept & convert uppercase input.

Holocene years were chosen for the more conscious and sensible epoch than Gregorian years, eliminating both negative years for the entirety of written human history and the year 0 problem. three digits were chosen for covering 0 HE to 46 655 HE (10 001 BCE to 36 655 CE), by which point humans will be extinct or using new calendars.

(j-dates are not intended to be used past 36 655 CE without a revision of the standard: earlier versions specified variable-width years, reducing advantages and increasing complexity for a future that will never come. four-digit years would satisfy till 1 679 615 HE, which is amusing and absurd.)

∴ valid years range from [000..zzz]

days elapsed were chosen for simplicity and sanity over the arbitrary, variable-length Gregorian months; standard leap year rules apply.

(keep in mind that days elapsed mean it’s zero-indexed, so 01 means “one day elapsed”, i.e. January 2nd.)

(day of year only uses 28% of its available ‘space’, but i can think of no good use for this: while it would be funny to store three years worth of days, it’d be so maddening to work with it’d render the entire format useless, especially when accounting for leap years; therefore, any day of year value above the number of days in that year renders the entire j-date malformed.)

∴ valid days of year range from [00..a5] on leap years, [00..a4] otherwise

deciseconds elapsed was chosen because there are 86 400 seconds in nearly every day (j-dates inherently handle leap seconds without problem, despite my contempt); a three-digit base 36 number maxes out at 46 655—obviously not enough—but four at 1 679 615: ample space to expand those seconds into deciseconds.

decisecond of day uses only 51% of its available space, and can be used past 863 999 for leap seconds or when a task continues past midnight, e.g. a train ride from 23:00–27:00.

∴ valid deciseconds of day range from [0000..zzzz], with [0000..iinz] belonging to the current day literally, [iio0..iio9] being an assumed or confirmed leap second, and [iioa..zzzz] belonging to the current day semantically.

valid j-dates range from 000000000 (−10000-01-01T00:00:00.0Z) to zzza4zzzz (+36655-12-31T46:39:21.5Z)

supplemental

j-date-int

AKA oh no j-di’nt: convert wholecloth to base 10 for use as 64-bit ints: 26162925722601

(for the extremely rare years before 1296 HE (8705 BCE), zeropadding is required after converting back to base 36 else the j-date is malformed.)

j-date-oic

chunk the j-date segments (first three for year, next two for day of year, and final four for deciseconds), convert each to base 10, divide deciseconds by ten, then join with hyphen-minuses: 12019-106-78692.1

(as with ISO 8601, . or , may be the decimal seperator.)

~fin