Changing the file creation date on macOS

If you modify a file in-place using sed with the -i option, you will get a file that has a new file creation date. On macOS 13.3.1, this is absolutely 100% true, although you will read claims otherwise. I ran into this problem while implementing a Hazel rule that updates YAML automatically in my Obsidian notes.

Background

I have use YAML frontmatter in my Obsidian notes. It looks like:

---
uid:     20221120152124
aliases: [20221120152124, AllAboutShell]
cdate:   2022-11-20 15:21
mdate:   2023-05-18 05:14
type:    zettel
---

My goal is to update the mdate field whenever the file changes. Hazel is the perfect tool for this, so I set about writing a rule that covers this case. The heart of the rule is a shell script action that writes the modification date:

FILE="$1"
# the date the file was modified
MODDATE=$(stat -f "%Sm" -t "%Y-%m-%d %H:%M" "$FILE")

sed -i '' -E "s/(modification date:).*/\1   $MODDATE/g" "$FILE"
sed -i '' -E "s/(mdate:).*/\1   $MODDATE/g" "$FILE"

It works well; but there’s one catch: sed allegedly is modifying the file in-place, but it does not, as evidenced by the fact that the file has a new creation date.

Why is the file creation date so important to maintain anyway?

If we’re working with notes in an Obsidian vault, this is what Dataview queries use to find notes created on a certain date. If I’m constantly re-creating notes with new creation dates, then I never have an accurate record of notes created on a particular date.

Solution

The solution, on macOS only, is to grab the file creation date, make our sed substitution, then re-apply the original file creation date. Fortunately in the Xcode command line developer tools (which you need to have installed) there are two utilities that can help here:

  • SetFile (also known as setfile)
  • GetFileInfo (getfileinfo)

GetFileInfo

Running GetFileInfo on an arbitrary file, we see:

➜  ~ GetFileInfo -d “archive.txt”
05/21/2023 07:09:21

SetFile

SetFile works in a similar fashion. We can update the creation date in this way:

➜  ~ SetFile -d "02/14/2023 06:00" “archive.txt”
➜  ~ GetFileInfo -d “archive.txt”
02/14/2023 06:00:00

Assembling a solution

Since we can now read and write the file creation date, we just need to bracket our YAML modification with GetFileInfo and SetFile calls. That way Obsidian will never see the change as a new file. The original shell script action in the Hazel rule now looks like:

# update the modified field, but in so doing, try to
# preserve the original creation date.

FILE="$1"
# the date the file was modified
MODDATE=$(stat -f "%Sm" -t "%Y-%m-%d %H:%M" "$FILE")

# get the file system creation date
CDATE=$(GetFileInfo -d "$FILE")

sed -i '' -E "s/(modification date:).*/\1   $MODDATE/g" "$FILE"
sed -i '' -E "s/(mdate:).*/\1   $MODDATE/g" "$FILE"

SetFile -d "$CDATE" "$FILE"

Now we can use sed inside a Hazel rule, modying the file whose content has changed without altering the file creation date. Obsidian then is happy; and I’m happy.

References

Flatten airports in X-Plane

Some airports in X-Plane have terrain issues that can be quite entertaining.

This Delta 737-800 got lost in the maze of cargo ramps at PANC and was trying to taxi back to the terminal when it encountered a steep icy taxiway. It required 65% N1 just to get up the slope.

Clearly a fix is required. It turns out to be quite simple. In the global airports file apt.dat, find the offending airport. In this case, it’s PANC where its entry looks like:

1    149 0 0 PANC Ted Stevens Anchorage Intl
1302 city Anchorage
1302 country USA United States
1302 datum_lat 61.174155556
1302 datum_lon -149.998188889
1302 faa_code ANC
1302 gui_label 3D
1302 iata_code ANC
1302 icao_code PANC
1302 region_code PA
1302 state Alaska
1302 transition_alt 18000
...

To flatten the airport terrain, add the line 1302 flatten 1 after the airport header, so that the block now looks like:

1    149 0 0 PANC Ted Stevens Anchorage Intl
1302 flatten 1
1302 city Anchorage
1302 country USA United States
1302 datum_lat 61.174155556
1302 datum_lon -149.998188889
1302 faa_code ANC
1302 gui_label 3D
1302 iata_code ANC
1302 icao_code PANC
1302 region_code PA
1302 state Alaska
1302 transition_alt 18000
...

But what about when X-Plane is updated; the global airport apt.dat file gets overwritten. My workaround is to apply the fix programmatically after update:

#!/bin/bash

APTDAT="/Users/$(whoami)/X-Plane 12/Global Scenery/\
Global Airports/Earth nav data/apt.dat"

perl -pi -e '$_ .= qq(1302 flatten 1\n) if /PANC\sTed.+/' "$APTDAT"

I suppose, I could create a custom airport directory for the airports that I flatten, but then I’d lose out on any future modificationsto those airports that Laminar Research publishes in its updates. I’ll have to think about that one.

Hazel deletes custom file icons, and a workaround

I use Hazel extensively for automating file management tasks on my macOS systems. Recently I found that Hazel aggressively matches an invisible system file that appears whenever you use a custom file or folder icon. I’ll describe the problem and present a workaround. In a handful of directories, I have a rule that prevents users (me) from adding certain file types. So the rule just matches any file that is not an image, for example, and deletes it.

AwesomeTTS Anki add-on: Use Amazon Polly

As its name implies, the AwesomeTTS Anki add-on is awesome. It’s nearly indispensable for language learners. You can use it in one of two ways: Subscribe on your own to the text-to-speech services that you plan to use and add those credentials to AwesomeTTS. (à la carte) Subscribe to the AwesomeTTS+ service and gain access to these services. (prix fixe) Because I had already subscribed to Google and Azure TTS before AwesomeTTS+ came on the scene, there was no reason for me to pay for the comprehensive prix fixe option.

Using fswatch to dynamically update Obsidian documents

Although I’m a relative newcomer to Obsidian, I like what I see, especially the templating and data access functionality - both that provided natively and through the Templater and Dataview plugins. One missing piece is the ability to dynamically update the YAML-formatted metadata in the frontmatter of Obsidian’s Markdown documents. Several threads on both the official support forums and on r/ObsidianMD have addressed this; and there seems to be no real solution.

Week functions in Dataview plugin for Obsidian

There are a couple features of the Dataview plugin for Obsidian that aren’t documented and are potentially useful. For the start of the week, use date(sow) and for the end of the week date(eow). Since there’s no documentation as of yet, I’ll venture a guess that they are locale-dependendent. For me (in Canada), sow is Monday. Since I do my weekly notes on Saturday, I have to subtract a couple days to point to them.

Scraping Forvo pronunciations

Most language learners are familiar with Forvo, a site that allows users to download and contribute pronunciations for words and phrases. For my Russian studies, I make daily use of the site. In fact, to facilitate my Anki card-making workflow, I am a paid user of the Forvo API. But that’s where the trouble started. When the Forvo API works, it works OK, often extremely slow. But lately, it has been down more than up.

A regex to remove Anki's cloze markup

Recently, someone asked a question on r/Anki about changing and existing cloze-type note to a regular note. Part of the solution involves stripping the cloze markup from the existing cloze’d field. A cloze sentence has the form Play {{c1::studid}} games. or Play {{c1::stupid::pejorative adj}} games. To handle both of these cases, the following regular expression will work. Just substitute for $1. {{c\d::([^:}]+)(?:::+[^}])}} However, the Cloze Anything markup is different. It uses ( and ) instead of curly braces.

Anki: Insert the most recent image

I make a lot of Anki cards, so I’m on a constant quest to make the process more efficient. Like a lot of language-learners, I use images on my cards where possible in order to make the word or sentence more memorable. Process When I find an image online that I want to use on the card, I download it to ~/Documents/ankibound. A Hazel rule then grabs the image file and converts it to a .

Altering Anki's revlog table, or how to recover your streak

Anki users are protective of their streak - the number of consecutive days they’ve done their reviews. Right now, for example, my streak is 621 days. So if you miss a day for whatever reason, not only do you have to deal with double the number of reviews, but you also deal with the emotional toll of having lost your streak. You can lose your streak for one of several reasons.