Automatically update last modified date in note

Is “history array” a descriptor for a “list of modified dates”?
Is a “history array” supposed to display in the properties/YAML? Or, does it show in some other area of Obsidian?

My hope is to see a “list of modified dates”, so I tried your suggestion. After adding a new property, “Date Modified”, I changed the frontmatterProperty in the data.json:

image

Now, instead of overwriting the “append_modified_update”, it’s overwriting the “Date Modified”:

I tried changing the “Date Modified” to a list and it didn’t make any difference. So, I changed it back to a “Date & Time”.

I don’t use any other community plugins, but if I can get yours to show a historical list of modified dates and times, I may take the huge leap into “trusting” a community plugin in my main Obsidian vault, rather than in a test vault.

Thanks in advance for your help.

You need to tick append_modified_update. I can see in your screenshot it’s a date, not a tick.

What is a “tick”?

The following shows that the append_modified_update is a checkbox:

image

Look at the purple tick in my screenshot. Remove the date from that field. You can see Obsidian has a warning icon on yours because it’s invalid.

This “thread” with AlanG was continued at:

Obsidian-frontmatter-modified-date: List of modified dates and times - Share & showcase - Obsidian Forum

When I rename a file within Obsidian and have “Automatically update internal links” on in the settings (on by default, I suspect), I don’t see a change in date modified, alas, neither using this nor using the other plugin.
It would be important because my DataView query (that compares publish update and modified dates) will not pick up on these internal link changes.

We really should have a core Obsidian way of handling all this…

1 Like

From the perspective of my plugin, that wouldn’t be considered a modification. I’m attempting to make “modifying” a file mean that you are inside the note intentionally working on it.

Using a plugin which is based off the filesystem modification time would work better in that case.

It was not meant to be a critique of the plugin.

It’s just that moving forward Obsidian needs to look after these things.
And it’s a known thing that core code is inspired by community plugin maker’s developments.
I see a Feature Request from two years ago, by the way and nothing was done yet.
For Obsidian Databases it will be important as well.

1 Like

Hey, I found the plugin really useful and did exactly what I was hoping. I had in the frontmatter a last modified field that now properly updates, in the date format I want.

Some time ago, I tried to find a way to also automatically update some other field that I have for tags, based on the <%tp.file.tags%>. It doesn’t update as I populate my note document with tags, but I was hoping there was a similar way to implement it for tags, as you did in this plugin for last modified time.

Do you think this would be possible?

Cheers

You need to specify the tag.

In my Templater script (which I launch from the mobile toolbar), I add the translation from the clipboard, do some operations on the text, insert it and create the tag if it doesn’t already exist:

<%*
clipboard = await tp.system.clipboard();
// Replace some content
clipboard = clipboard.replace(/\s-\s/gi, " – ");

if (clipboard.startsWith("> ")) {
    tR += "\n> —  \n" + clipboard;
} else {
    tR += "\n—  \n" + clipboard;
}

// Check if the 'Englishtexttranslated' tag exists before adding it
setTimeout(() => {
  app.fileManager.processFrontMatter(tp.config.target_file, frontmatter => {
    if (!frontmatter['tags'] || !frontmatter['tags'].includes('Englishtexttranslated')) {
      const tagsArray = Array.isArray(frontmatter['tags']) ? frontmatter['tags'] : [];
      if (!tagsArray.includes('Englishtexttranslated')) {
        tagsArray.push('Englishtexttranslated');
        frontmatter['tags'] = tagsArray;
      }
    }
  });
}, 350); // Timeout to allow preceding clipboard operations to complete
_%>
  • Forget about the first part of the script that you obviously don’t need and exchange Englishtexttranslated with your own tag. You can add more than one property here of course.

Some part of the script I nicked from Alan before. :wink:

1 Like

Also, when one makes batch replacements, I don’t know of a program that would help me update the date modified field (so as to, again, have those reflect on my DataView query).
I need to make a habit of not using Notepad++ or other programs for regex replacements and use a Python script that updates my date modified field (didn’t opt for the yaml or frontmatter Python libraries; they entailed too many problems):

import os
import re
from datetime import datetime

# Function to perform replacements with regex and update date modified
def update_and_save(file_path, replacements, regex_pattern, replacement_text):
    with open(file_path, 'r', encoding='utf-8') as file:
        content = file.read()

    # Check if the file needs regex replacements
    needs_replacement = bool(re.search(regex_pattern, content))

    # Only modify the file if replacements are needed
    if needs_replacement:
        # Perform regex replacements
        content = re.sub(regex_pattern, replacement_text, content)

        # Find and replace 'date modified' line with current date in YYYY-MM-DD format
        pattern = r'date modified: \d{4}-\d{2}-\d{2}'
        current_date = f'date modified: {datetime.now().strftime("%Y-%m-%d")}'
        content = re.sub(pattern, current_date, content)

        # Save updated content to the file
        with open(file_path, 'w', encoding='utf-8') as file:
            file.write(content)
            print(f"Updated date modified and performed regex replacements in {file_path}")

# Root directory containing Markdown files
root_directory = '/home/<user>/Obsidian/<vaultname>/'

# Regex pattern and replacement text for replacements
regex_pattern = r'(\[\[)(.*?)(\]\])'
replacement_text = r'\2'

# Iterate through directories matching the specified regex pattern within the root directory
for dir_name in os.listdir(root_directory):
    dir_path = os.path.join(root_directory, dir_name)
    if os.path.isdir(dir_path) and re.match(r'regextofilterforfolders', dir_name):
        # Iterate through each file in the directory
        for filename in os.listdir(dir_path):
            if filename.endswith('.md'):
                file_path = os.path.join(dir_path, filename)
                update_and_save(file_path, None, regex_pattern, replacement_text)
  • My YAML key is date modified. I ran the script on Linux. I just picked a random regex replacement for the sake of this post so one can see the syntax used by Python. One needs to specify root/vault path and the subdirectories with regex.

Not a long-time Python user. Let’s say this is my 3rd or 4th .py script ever run by me, so if I can do it, anyone can. No installment of further libraries are necessary.

Hi Alan - Just want to thank you for this plug-in. Does exactly what I was looking for. :+1::+1:

1 Like

@AlanG Can I specify the time to be always UTC? If so could you point me in the right direction?

For anyone else coming across this thread, the Obsidian Liner plugin has this feature built-in.

See the “YAML Timestamp” section of the Obsidian Linter documentation for details.

Linter – much as I like the plugin and the ever helpful developer/caretaker of it – updates the modified date from file system data, which means it can update the YAML of a file when you don’t even make a change in it.
Which is annoying if you enter published files and when you run a Dataview query, you’ll see you should need to manually re-publish 30-40 files when you know fully there were no changes made in (all of) them, you just perused (at least some of) them.

It’s okay if you use “lint on save”, though. The trouble I faced – mentioned above – is when I used “lint on file change.” The interpretation of file change is based on the every 2 second auto save of Obsidian, so there’s nothing our good man can do.

So if you need to remember to save (hence lint on save), you might as well run a Templater script that updates the date modified…

1 Like

Thanks a lot!

Maybe you should post a topic about your plugin somewhere in the forum to advertise it :slight_smile:

I have a question, I had created and used the following Templater script based on this thread.

<%*
setTimeout(() => {
  app.fileManager.processFrontMatter(tp.config.target_file, frontmatter => {
	if (!frontmatter['created']){
		frontmatter['created'] = tp.file.creation_date('YYYY-MM-DD');
	}
	if (!frontmatter['modified']){
		frontmatter['modified'] = tp.file.last_modified_date('YYYY-MM-DD');
	} else {
		frontmatter['modified'] = tp.date.now('YYYY-MM-DD');
	}
	if (!frontmatter['tags']){
		frontmatter['tags'] = null;
	}
	if(!frontmatter['file_type']){
		frontmatter['file_type']=null;
	}
  });
}, 200) 
-%>

(This script creates some properties if they do not exist in the note, and for the created and modified properties, it either gets the date from the system or changes it to today’s date.)
It worked fine until yesterday, but today I noticed that when I apply this script to a note where no properties exist, it outputs plain text without any ---, as shown below, and no properties are created.

created: 2024-02-15
modified: 2024-02-15
tags:  
file_type: 

For notes that have at least one property, I am still getting the expected behavior.
As far as I have tried, the script works correctly in Obsidian v1.5.4, and appears to have the above problem in Obsidian v1.5.5.
I have looked in Obsidian’s Changelog, but could not find anything that might be related. I have looked in Obsidian’s Changelog and could not find anything that might be related to this.
If anyone knows the cause, please let me know.

I’m not using processFrontMatter in my templates, but it would be strange that it worked until 1.5.5

I can’t help fix this, but thought I’d offer up a gem as a way to deal with your date stamping: Update time on edit plugin

1 Like

@iiz @gregp Apologies this did seem to get broken in the last update due to an internal refactor. I have a fix ready that will ship in the next build.

5 Likes

I’m also hoping the app.fileManager.processFrontMatter function will never be changed as many many people’s workflow depend on it and regulars and other frequent posters keep mentioning this method for property updates.

Cheers

2 Likes