I’ve been using Obsidian as the primary hub for personal notes for the past year. My daily notes act as a sort of captain’s log, and have superceded my use of a dedicated journaling app. So I exported all my journal entries to markdown, and added them to my Obsidian vault as daily notes.
In the process of migrating journal entries between apps over the years1, I must have messed up some metadata at some point, because I just realized today that all my entries before a certain point in time were wrong by one day. So I wrote a small script (below) to batch correct these files.
To help write and debug the script, I put a handful of dummy files in a
staging directory, each following the
YYYY-MM-DD.md naming convention.
pathlib.Path(…).glob('*.md') to get a list of markdown files in this directory.
import datetime as dt from pathlib import Path
p = Path('staging') all_md_files = sorted(list(p.glob('*.md'))) # Print the contents of each file for f in all_md_files: print('\n' + '=' * len(f.name)) print(f.name) print('=' * len(f.name) + '\n') with open(f, 'r') as open_file: print(open_file.read())
============= 2013-12-31.md ============= # 2013-12-31 This file should become 2014-01-01. ============= 2014-01-01.md ============= # 2014-01-01 This file should become 2014-01-02. ============= 2014-01-03.md ============= # 2014-01-03 This file should remain as 2014-01-03.
Note that these files contain the date in their names, but also as an
h1 heading within the file itself, so we’ll need to change both.
My original issue only affected files up to a certain date, so let’s filter the list of markdown files.
Because we are incrementing the dates of files, we’ll want to work through the list in reverse order. Before making yesterday today, we must make today tomorrow—else there will be a conflict.
selected_files = sorted([f for f in all_md_files if f.stem <= '2014-01-02'], reverse=True) for f in selected_files: print(f.name)
The actual work to be done here is relatively simple:
- Convert string to datetime, increment by 1d, convert back to string.
- Replace references to the previous date string with the new one, inside file contents.
- Rename the file itself.
def replace_in_file(fp: str, old: str, new:str) -> None: """ Replace 'old' strings with 'new' strings in a given file (fp) """ with open(fp, 'r') as open_file: old_contents = open_file.read() new_contents = old_contents.replace(old, new) with open(fp, 'w') as open_file: open_file.write(new_contents) for f in selected_files: old_dt = dt.datetime.strptime(f.stem, '%Y-%m-%d') new_dt = (old_dt + dt.timedelta(days=1)) new_ds = new_dt.strftime('%Y-%m-%d') replace_in_file(f, f.stem, new_ds) f.rename(f.parent / (new_ds + '.md'))
Visually inspecting the files in the
staging directory, we can see the final result matches what we hoped to achieve.
for f in sorted(list(p.glob('*.md'))): print('\n' + '=' * len(f.name)) print(f.name) print('=' * len(f.name) + '\n') with open(f, 'r') as open_file: print(open_file.read())
============= 2014-01-01.md ============= # 2014-01-01 This file should become 2014-01-01. ============= 2014-01-02.md ============= # 2014-01-02 This file should become 2014-01-02. ============= 2014-01-03.md ============= # 2014-01-03 This file should remain as 2014-01-03.
If you’re running a script that modifies your files in-place like this, be sure to have recent, working backups before you start, in case something goes wrong!