Subscripts for Dates

1

The secret to making friends? Don’t make people do mental math. Or at least, don’t ask me to. As a party trick, I calculate percentages (e.g. “what’s 22.3% of 700?”)—but some days I refuse because I’m sluggish and worry I’ll look like a fraud. In the same vein, I often read about events that took place in some year like 1564 or 1876 or 1958 and the first thing I want to know is how long ago it was. The cognitive load requirement is frustrating and distracting. I’m not alone here. I posit that most people have terrible time-depth perception. Usually when I hear a birthdate—say 1981—here’s how my mental math works: 19 years to 2000 -> 25 years to 2025 -> 19 + 25 -> -1 + 20 + 25 -> -1 + 45 -> 44. I find that whoever I’m around takes roughly the same amount of time to compute the age.

This problem never entered my awareness until today. I happened upon Gwern Branwen’s post on why Denmark never sold Greenland. (It’s become topical again due to America’s renewed interest in buying it.) I was first introduced to Gwern on Dwarkesh’s podcast, where he’s described as “one of the most interesting polymathic thinkers alive”. His posts are exhaustive articles that go deep on a wide range of topics. This verbose style extends to his website, which you’ll either find incredible or overwhelming. For example, when you hover over a link to a Wikipedia page, a window pops up so you can quickly skim that page. In that Denmark article, I saw an ingenious use of the subscript:

When I first saw the 79ya, I ignored it as some weird citation format. But like two seconds later I autonomically decoded it: 1946 was 79 years ago. I thought, this Gwern guy’s a genius. My time-depth perception problem had been solved. I found Gwern’s rationale for his use of relative time subscripts. He argues that it fights against “mental slippage” — a historical date like 1972 “may be relevant for its distance from the present moment” requiring readers to mentally calculate the difference, “which one will often not do”. In short, the relative time subscript reduces the cognitive load requirement and enriches context.

Having the relative time next to the absolute time is super useful for building context. Consider this: Trump is trying to buy Greenland and a lot of people think that’s insane, but it’s already been attempted 79 years ago. The relative time is far more meaningful than “1946” because your brain doesn’t have to decode how long ago that was. I bet most readers won’t bother with decoding anyway, and instead think of the 1946 offer as something that merely happened a long time ago. Having a concrete understaning of how far it was in relative terms builds your context. 79 years? That’s really not that long ago. Could this Greenland deal actually have some merit? It’s like how in movies the viewer gets an establishing shot to communicate the location—for example, you always see the London Bridge to “place” the story in London. If you didn’t get that establishing shot, you’d have to pick up on cues like accents, buses or cabs. Seeing the relative time difference is like seeing an establishing shot.

2

Let’s make the absolute relative again.

I want absolute years to be accompanied by the relative time ago. If I write “2000”, I want it to automatically appear as “2000”. But I don’t want “$2000” to appear as “$2000”. Gwern notes that this is rather simple: use regular expressions to match “4-digit whole numbers starting 1–2 and surrounded by non-digits”. Easy enough, let’s do it.

First, I want to target specific values (e.g. 2000 vs $2000). I think it’s appropriate to use <sub> tags to wrap the target values. Why not use <span> with a unique id? Because then I have to remember that. I rarely use <sub>, but more importantly I would most likely never use it to subscript a four digit number. Second, I want it to “just work” and run automatically. That can be accomplished by using an event listener and running the code once the HTML is parsed.

Here’s my implementation:

document.addEventListener('DOMContentLoaded', () => {
  document.body.innerHTML = document.body.innerHTML.replace(
    /<sub>(\\d{4})<\\/sub>/g,
    (_, year) => \`\${year}<sub>\${new Date().getFullYear() - year}ya</sub>\`
  );
});

The code automatically runs once the HTML document has been parsed, but doesn’t wait for things like images or async scripts to load. Then it uses a regular expression to select and replace all instances of four digit numbers in <sub> tags. Finally, it composes a new string with a <sub> tag containing the relative time.

So now I can tell you that the iPhone came out in 2007, or that the Wright Brothers’ first successful and sustained airplane flight was in 1903. The Great Fire of London ravaged the city in 1666, Shakespeare wrote Romeo and Juliet around 1595, and the first successful summit of Mount Everest occurred in 1953. The Berlin Wall fell in 1989, while the first text message was sent in 1992.

That’s awesome.

Gwern ups the ante by subscripting time deltas:

1987-1994 was 30 years ago and lasted 7 years.

This example communicates that the time range 1987-1994 was 30 years ago and lasted 7 years. Gwern explains how to do this: “subscript the EN DASH itself”. In addition to that, Gwern uses custom CSS rules to align the duration value directly under the en dash.

Here’s what it looks like without CSS:

19877199430ya

Here’s what it looks like with those extra CSS rules:

19877199430ya

Here’s how to ammend the code to support this functionality:

document.body.innerHTML = document.body.innerHTML.replace(
    /<sub>(\\d{4})-(\\d{4})<\\/sub>/g,
    (_, startYear, endYear) => \`\${startYear}<span class="subscript-range"><sup>–</sup><sub>\${endYear - startYear}</sub></span>\${endYear}<sub>\${new Date().getFullYear() - endYear}ya</sub>\`
  ).replace(
    /<sub>(\\d{4})<\\/sub>/g,
    (_, year) => \`\${year}<sub>\${new Date().getFullYear() - year}ya</sub>\`
  );

It looks for four digits numbers separated by an en dash and contained within <sub> tags.

So now I can tell you that the Cold War lasted from 1947–1991, while the California Gold Rush brought prospectors west during 1848–1855. The Great Depression gripped America from 1929–1939, and the Renaissance flourished in Europe from 1300–1600.

That’s awesome.

3

“I gotta go bananas one time” — Jordan Carter

One more things...

What if you want higher resolution? For example, Ross Ulbright was pardoned January 21, 2025. Our relative-time subscript from above doesn’t really work here as it would (at time of this writing) appear as 20250ya. But it would be helpful to see the days ago…

View amended code
function getRelativeTime(dateStr) {
  const date = new Date(dateStr);
  const now = new Date();
  const diffTime = now - date;
  const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));

  if (diffDays < 0) return 'in the future';
  if (diffDays <= 31) return \`\${diffDays}d ago\`;
  if (diffDays <= 90) return \`\${Math.round(diffDays/7)}w ago\`;
  if (diffDays <= 365) return \`\${Math.round(diffDays/30)}mo ago\`;
  return \`\${Math.round(diffDays/365)}y ago\`;
}

document.body.innerHTML = document.body.innerHTML
  .replace(
    /<sub>(\\d{4})-(\\d{4})<\\/sub>/g,
    (_, startYear, endYear) =>
      \`\${startYear}<span class="subscript-range"><sup>–</sup><sub>\${endYear - startYear}</sub></span>\${endYear}<sub>\${new Date().getFullYear() - endYear}ya</sub>\`
  )
  .replace(
    /<sub>(\\d{4})<\\/sub>/g,
    (_, year) => \`\${year}<sub>\${new Date().getFullYear() - year}ya</sub>\`
  )
  .replace(
    /<sub>([A-Za-z]+ \\d{1,2},? \\d{4})<\\/sub>/g,
    (_, dateStr) => \`\${dateStr}<sub>\${getRelativeTime(dateStr)}</sub>\`
  );

So now I can tell you Ross Ulbright was pardoned January 21, 2025. Or that Anthropic released Claude on Jun 20, 2024. Or that I ate pizza for dinner on Dec 20, 2024.

I think we can stroll further down this road and find all sorts of creative ways to enrich context using subscripts.

  • Contextualizing population dynamics: “Japanpop. 124m is facing a fertility crisis”
  • Contextualizing movies and ratings: “InterstellarIMDb 8.7/10 is my favorite movie”
  • Contextualizing book lengths: “I prefer The Stand1152 pages more than The Shining447 pages
  • Contextualizing metric and imperial units: “it’s 22°C72°F outside”.
  • Contextualizing economies: “EstoniaGDP 40b and NepalGDP 40b have a strong bilateral relationship

For many of these, you’d need access to an API to fetch the latest values, or your context becomes stale and pointless. I suspect, however, if you’re the kind of person who’s motivated to use contextual subscripts, that won’t be much of an issue for you.

4

Subscripts are great tools to make one’s writing more readable. Obvious limitations is that you can’t use realtime subscripts on printed paper, or that archived webpages may not honor the Javascript code. So subscripts work best in internet publications in cases where you’re expressing secondary info that isn’t critical to the writing. You could extend the implementation to include graceful fallbacks—like alt attributes on image tags.

It’s completely possible that I’m lying to myself about how important subscripts are for context. Maybe I’m just in the minority of folks that gets caught in the details and is spurned by the cognitive load of mental math. If that is the case, it might be smarter to make a browser extension that renders contextualized subscripts. Think of it as push vs pull. For example, driving to the grocery store is “push” whereas having groceries delivered to you is “pull”. Spreading the gospel of subscripts is “push” and magically applying subscripts on every website you visit is “pull”.

frfr.blog

Babbling on the DL