Pragmatism in the real world

Set a file's created date from YAML front matter in macOS

I have a set of Markdown files with YAML front matter that contains a created property containing the date that the file was created. Due to various machinations, the file creation date no longer matches this date, so I thought I’d fix this.

Setting created date of a file

On macOS, to change a file’s creation date you use SetFile which is installed as part of Xcode. Irritatingly, it uses US format dates:

SetFile -d "01/31/2022 11:12:13" test.md

You can use GetFileInfo to read the information:

$ GetFileInfo test.md
...
created: 01/31/2022 11:12:13
modified: 11/01/2023 08:56:19

This is another utility that uses US format dates… sigh!

Reading YAML front matter with yq

To parse YAML on the command line, Mike Farah‘s yq is an excellent choice of tool to use. It even has a switch to read front matter only:

$ yq --front-matter="extract" test.md
---
created: 2021-01-21 01:02:02
tags:
  - test

We can the filter to get just the date we need:

$ yq --front-matter="extract" e ".created" test.md
2021-01-21 01:02:02

Note that yq will error if there’s no front matter block in the file.

Putting it together

We can now put this together to make write a script that sets the creation date of a file from it’s created front matter property:

#!/usr/bin/env bash

set -eo pipefail

file="$1"
if [[ -z "$file" ]] ; then
    echo "Usage: $(basename $0) "
    exit 1
fi

chars=$(head -c 3 "${file}")
if [ "$chars" != "---" ] ; then
    echo "No front matter section in file"
    exit 2
fi

created=$(yq --front-matter="extract" e '.created' "${file}")
us_format_created=$(date -j -f "%Y-%m-%d %H:%M:%S" "$created" '+%D %T')

echo "Setting file creation date to '$created'"
SetFile -d "$us_format_created" "${file}"

The bulk of the script is niceties where we ensure that a filename is passed as the first parameter and that there is a front matter section in the file. Then we extract the created date using yq, reformat it to US date format and then call SetFile to set the creation date of the file.

One final note, this script is very much macOS specific, not only for its use of SetFile, but also the BSD version of date.

Summing up

One thing I have noticed is that it’s really easy for the file’s creation date to be lost over its lifetime. Storing the creation date within the file shouldn’t be necessary, but if you want that information over the long term, store it in the file contents as metadata (e.g. in front matter) or encoded into the filename.

It’s useful to be able to put the date back into the OS’s metadata as sorting on the command line or in GUI tools will then work.