Nick Jones

Astro JS: Handling dates in blogposts

Nice astro graphic

First, the helpful hint

When you’re putting dates in the frontmatter of your posts in an AstroJS blog, do yourself a favor and add T12:00:00 to your time stamp. It corrects for the UTC offset so your dates don’t display as off by one day.

Some background

As I’ve built this site with Astro, I’m rediscovering how much I loved web development before React 1. I’m also remembering how it’s possible to go around and around on a single problem for an entire day, and find a solution in the obscurest corner of the web.

One of my favorite aspects of the Astro framework is its folder-based routing. Astro can connect to your database-as-a-service du jour, of course; but your blog can also just be a folder full of Markdown files served up on the fly with some frontmatter and TypeScript validation to stick it all together.

It’s really slick, and in total it’s been one of the best developer experiences I’ve had since the glory days of Rails (which has tragically become a trainwreck to use.) My only issue was with outputting dates.

The Astro way of blogging in Markdown involves adding frontmatter to posts:

---
title: 'My awesome post'
subtitle: 'This is so cool'
pubDate: 2023-04-18
---

This frontmatter is part of the schema you define using the Astro content module (using Zod under the hood). TypeScript then validates the schema as you save and author your Markdown files.

// Import utilities from `astro:content`
import { z, defineCollection } from "astro:content";
// Define a `type` and `schema` for each collection
const postsCollection = defineCollection({
    type: 'content',
    schema: z.object({
      title: z.string(),
      subtitle: z.string(),
      pubDate: z.date(),
    })
});
// Export a single `collections` object to register your collection(s)
export const collections = {
  posts: postsCollection,
};

Later you can iterate over the collection and render all the collection elements, maybe in a nice component with some styling.

<div class="container mx-auto p-8">
  {
    allPosts.map((post) => (
      <BlogPost 
        url={`/notes/${post.slug}/`} 
        title={post.data.title} 
        image={post.data.image} 
        date={post.data.pubDate}
      />
    ))
  }
</div>

The problem

My issue was in the way Javascript handles dates. I was using a date like

---
pubDate: 2023-11-16
---

and transforming it like

date = pubDate.toString().slice(0,10)

and getting output like

Published on: 2023-11-15

The state of getting answers about broken code on the web is weird at the moment. AI is taking over, and places like Stackoverflow and GitHub Issues are turning into ghost towns. Even so, I was able to find out enough to see that the issue was UTC timestamps and how they’re interpreted in a user’s browser.

So I did what everyone does these days: I described the issue to ChatGPT.

I got some good, thorough results but nothing was getting me over the hump. ChatGPT correctly understood the problem, and was making a valiant effort to write some code that would solve it. But it wasn’t until I read an offhand line in one of its responses that I realized the solution was as simple as adding T12:00:00 to the date in the frontmatter.


Footnotes

  1. Astro is Javascript, after all — but it outputs HTML in all but the most extreme cases. Writing Astro templates is a lot more like writing good old HTML than spaghetti JSX, and I like that.