How do I get LogSeq page creation date to equal creation date of actual .md file?

I created a completely new graph for testing and then I dragged into the “pages” folder one markdown file that has a creation date from a few weeks ago. When I view this page in the “pages” list inside LogSeq app, however, it says that the creation date is today. I had thought LogSeq displayed the files creation date and not the date that file is imported? Is there a way to have LogSeq use the actual files creation date? (I am saying this because I have another graph that I reindexed and doing this changes are page creation dates to the current date. I am also seeing that the “pages-metadata.edn” file is no longer used so I am curious where this data is stored.

Thanks for any help and all your hard work on LogSeq!

Hi @BenjiFrank. I found the creation date of a page can be overridden by adding a creation-date:: property to the first block in the page. (It will not be visible in the Logseq editor afterwards.) The date format is unix time with milliseconds (just add 000 to the end of the unix time).

What is your platform? This is easy to compute on Mac OS, but you need to install a command line like WSL, Git Bash, or Cygwin if you are using Windows. And how many files do you want to change? If you have fewer than 30, I suggest doing it by hand. If you have more, I or someone else could write a perl script to do it automatically, but you may need to install Perl in addition to setting up a command line.

@palindrome: Man! Thank you for getting back to me. Is using this property method written about in the LogSeq documentation somewhere? I am surprised the method isn’t simpler. I have 1302 pages and the create date is wrong on all of them so some better, automated way would certainly be best. Having the proper creation dates does end up being very important for me. Thanks for your sharing on this. I have posted about this elsewhere too and you’re the only one who has stepped forward!

Hi @BenjiFrank. I discovered it by turning on developer options and right clicking the page to see page properties. creation-date was one of the properties and I was curious if it was exactly the same as the kind of property you can manually write in the first block of the page.

I’ll probably be busy for a few days, but this doesn’t seem too hard to automate with a perl or python script.

Thanks, @palindrome. Yeah, I’m pretty desperate to get this fixed. I have lost some momentum in my love of LogSeq because of how challenging and time consuming its been to try to find a solution. I have turned on dev mode now and I see the “Show Page Data” link but it doesn’t look like it’s editable directly so if your method is the only and best/ most efficient way I am all for it and maybe others like me could benefit too! Optimally it could just pull the actual creation/modification date for the file and then use this value. I feel like LogSeq would be better served by just using this meta information in the first place.

You mean adding a bullet like this that has “000” appended. I did this manually on one and then went back to the page list view to view the creation date but it remains unchanged there, even after closing the app and reopening. Likely doing it wrong. Thanks again for the input here @palindrome

Screen Shot 2023-02-01 at 1.40.22 PM

That doesn’t look like a correct date. The number should be the milliseconds since Jan 1, 1970. It’s pretty standard (but usually seconds. milliseconds is uncommon).

Try 1675479249000. Also, it must be part of the first block in the page, at the beginning of a line. And I needed to re-index pages before the new date showed up. (Also, this change is permanent. After re-indexing you can remove this property and the new value will stick, unless of course you repeat the procedure.)

Try this script to batch modify all your files. Back them up first! This script does back up files to a “bak” directory, but it’s hard to catch every possible potential problem during testing.

To run it, put this code in a file called “add-creation-date.pl” in your logseq pages directory. If you’re on Windows, install Strawberry Perl and open the script with Strawberry Perl. (If it gives you an error about the path not being a “pages” directory, tell me and I will modify the script to prompt you for the path.)

You can also tell me if it fails on more than a few of your files, and give some examples of the files: I’ll need to see the first and second block (at least including the 1st line of the 2nd block).

This script does not do what is hoped, do not try it. However I am leaving it up as an example of how to add any property to a bunch of pages using a script, while preserving their data:

#!/usr/bin/env perl
# Add created-at property to markdown files, for Logseq.
# The date is the file's creation time as milliseconds since the Unix epoch.

use strict;
use warnings;
use v5.28;

use Cwd;
use File::Find;
use List::Util qw(any tail);

sub add_creation_date;
sub add_creation_date_to_block;
sub add_creation_date_as_property;
sub add_on_line;

if (substr(getcwd, -6) !~ qr<[/\\]pages>) {
    say STDERR "For safety, this script must be run in a 'pages' directory";
    exit(-1);
}

find(sub {
    if (substr($File::Find::dir, -4) !~ qr<[/\\]bak> && -f && /\.md$/) {
        add_creation_date $_;
    }
}, '.');

our @contents;
our $file;
our $line_ending;
our $ctime;

sub add_creation_date {
    our $file = $_[0];
    open(my $fh, '<', $file) or die "Cannot open file. $!";
    our $ctime = (stat _)[10] * 1000;
    our @contents = <$fh>;
    close $fh;

    if (scalar @contents) {
        if (substr($contents[0], -2) eq "\r\n") {
            $line_ending = "\r\n";
        } else {
            $line_ending = "\n";
        }

        if ($contents[0] =~ /^[\w-]+::/) {
            add_creation_date_as_property;
        } elsif (substr($contents[0], 0, 1) eq '-') {
            add_creation_date_to_block;
        } else {
            # We don't understand the format:
            say STDERR "First line is not a block nor a properties list, skipping $file";
            return;
        }
    }
}

sub backup_file {
    our $file;
    our @contents;

    my $backup_path = "bak/$file";
    if (-e $backup_path) {
        say STDERR "Skipping file because backup file already exists: $backup_path";
        return 0;
    }
    say "Backing up and adding creation date: $file";
    mkdir "bak";
    #rename $file, $backup_path or die "Cannot rename file. $!";
    open(my $fh, '>', $backup_path) or die "Cannot open backup file. $!";
    print $fh @contents;

    1;
}

sub add_creation_date_as_property {
    our $file;
    our @contents;
    our $line_ending;

    # skip the first line as it is the block start:
    my $first_block_len = 1;
    while (1) {
        if ($first_block_len == scalar @contents || $contents[$first_block_len] =~ /^\s*(-|$)/) {
            last;
        } elsif ($contents[$first_block_len] =~ /^\s*created-at::/) {
            say STDERR "First block already contains a creation date, skipping $file";
            return;
        }
        $first_block_len += 1;
    }

    add_on_line $first_block_len, "", "";
}

sub add_creation_date_to_block {
    our $file;
    our @contents;
    our $line_ending;

    # skip the first line as it is the block start:
    my $first_block_len = 1;
    while (1) {
        if ($first_block_len == scalar @contents || $contents[$first_block_len] =~ /^\s*-/) {
            last;
        } elsif ($contents[$first_block_len] =~ /^\s*created-at::/) {
            say STDERR "First block already contains a creation date, skipping $file";
            return;
        }
        $first_block_len += 1;
    }

    my @first_block = @contents[0..$first_block_len - 1];
    if (any { m/^\s*[\w-]::/ } @first_block) {
        # This block contains a tag, so we should add it to the existing block
        add_on_line $first_block_len, "  ", "";
    } else {
        # We can add it as a new property block on the first line, with a new blank line
        add_on_line 0, "", $line_ending;
    }
}

sub add_on_line {
    my ($first_block_len, $prefix, $suffix_line) = @_;
    our @contents;
    our $file;
    our $ctime;

    if (!backup_file) {
        return;
    }

    # Overwrite the file with the modified version:
    open(my $fh, '>', "$file") or die "Cannot open file for writing. $!";
    # Print the whole first block, not including children:
    print $fh @contents[0..$first_block_len-1];
    # Print an extra line with the creation date:
    print $fh "${prefix}created-at:: $ctime$line_ending";
    print $fh $suffix_line;
    print $fh @contents[$first_block_len..(scalar @contents - 1)];
    close $fh;
}

Oh wow! @palindrome: You’re incredible. I still, however, don’t seem to be able to get one pages to update. What I did:

1] Added creation-date:: 1675479249000 to the first block on a page I wish to update
2] Reindex the page
3] Check that page for date update after finished updating

Result: Same date remains.

Image example:

Ouch. I hate to say it after giving you hope, but after harder testing, this technique actually doesn’t work. First of all, I got the name mixed up: “creation-date” should be “created-at”. But more importantly, I tested this with a text editor, and I must have tested by changing the date to the current time. However the text editor reset the file’s creation date, so by coincidence my test case appeared to work. I’m sorry.

But because of this testing, I can more confidently say that the program actually is showing you the creation date (at least on Mac OS). It’s likely that during your backup/restore process, the creation date got messed up. There may be a way to correct it based on a reference file (another copy), but I can’t do it with a perl script.

Also, any time I edit my files with a text editor, the creation date gets reset. Your editor may be different. (Logseq itself preserves the creation date when editing, of course. A modification with perl also preserves it, at least on Mac OS and Linux.)

Oh man, thanks @palindrome … really appreciate your help and effort here. Man!

Every time I “Re-Index” the creation date and mod date are updated to the current date-time. This just seems like totally sub-optimal behavior. I would think everyone would want to preserve the actual creation date-time of their pages in the “All Pages” view so they can sort their notes chronologically.

I guess I am hoping someone chimes in with an additional idea here. I am currently losing LogSeq momentum as a result of this.

Do you know, @palindrome, if re-indexing is supposed to reset all your Creation and Modification Dates in the page list view? I am just wondering if this is something that has gone from on my Mac-based setup or if this is the intended outcome.

If this is intended, I’d love to hear from someone why this is preferred or good? I would think that that mirroring the actual creation date of the markdown file would be desired.