Macro that takes two dates and outputs a list of in-between dates

I need a macro that takes two parameters namely start-date and end-date and outputs a list of all dates from start-date to end-date, in the format that the user has setup in the config.edn file.

I presume that it could use an advanced query…

It should be invoked like so:

{{dates [[Wednesday, 08.05.2024]] [[Sunday, 12.05.2024]]}}

and it’s output should be:

[[Wednesday, 08.05.2024]] [[Thursday, 09.05.2024]] [[Friday, 10.05.2024]] [[Saturday, 11.05.2024]] [[Sunday, 12.05.2024]]

Could this be done with an Advanced Query?

Macros don’t play well with special characters like brackets and commas.

It can be done with an advanced query, but it needs work.

Can I dare to ask? :slight_smile:

I would guess one has to look for days in between those ?start-day and ?end-day by block/journal-day property and add it to a list somehow. No idea how it can be done but from my pov this feature would be very useful for making some reminder that would pop-up as a reminder for several days in a row. I can think of marking holidays just for an example.

Another way to do this would be by means of javascript, where some function that would be executed with the :evalparent macro would take the first and end dates and would calculate dates in between and add to a list/array the dates and output them to screen…

I’ve given this some thought and I believe this should really be some sort of kit that uses some datascript queries inside javascript but it beats me how to write such a thing… :-/ Can you help with such a function?

ok, I came up with some javascript code that works but I can’t figure out how to use it in a macro or how to modify the “kit / code” so that I can write:

{{int [[Monday, 27.05.2024]], [[Monday, 03.06.2024]]}}

and it outputs:

[[Monday, 27.05.2024]] [[Tuesday, 28.05.2024]] [[Wednesday, 29.05.2024]] [[Thursday, 30.05.2024]] [[Friday, 31.05.2024]] [[Saturday, 01.06.2024]] [[Sunday, 02.06.2024]] [[Monday, 03.06.2024]]

This is the Logseq Page: “datesInterval”:

function convertToDateObject(dateString) {
    // Strip the outer brackets from the dateString
    const trimmedDateString = dateString.slice(2, -2);
    
    // Extract day, date, month, and year from the trimmedDateString
    const [, day, date, month, year] = trimmedDateString.match(/(\w+), (\d{2})\.(\d{2})\.(\d{4})/);
    
    // Create a JavaScript Date object
    const dateObj = new Date(`${month}/${date}/${year}`);
    
    return dateObj;
}

function getAllDatesBetween(startDate, endDate) {
    // Initialize an array to store all dates
    const allDates = [];
    
    // Set the start date as the current date
    let currentDate = new Date(startDate);
    
    // Loop until the current date is less than or equal to the end date
    while (currentDate <= endDate) {
        // Add the current date to the array
        allDates.push(new Date(currentDate));
        
        // Move to the next day
        currentDate.setDate(currentDate.getDate() + 1);
    }
    
    return allDates;
}

function formatDateToLogseqJournalName(date) {
    // Get the day of the week
    const dayOfWeek = date.toLocaleDateString('en', { weekday: 'long' });
    
    // Get the day, month, and year
    const day = date.getDate().toString().padStart(2, '0');
    const month = (date.getMonth() + 1).toString().padStart(2, '0');
    const year = date.getFullYear();

    // Format the date string
    return `[[${dayOfWeek}, ${day}.${month}.${year}]]`;
}

// const dateStr1 = "[[Monday, 27.05.2024]]";
// const dateStr2 = "[[Monday, 03.06.2024]]";
dateStr1 = $1
dateStr2 = $2

const dateObj1 = convertToDateObject(dateStr1);
const dateObj2 = convertToDateObject(dateStr2);

const allDates = getAllDatesBetween(dateObj1, dateObj2);
const formattedDates = allDates.map(date => formatDateToLogseqJournalName(date)).join(" ");

console.log(formattedDates);

I am trying to create the macro in config.edn:

 :int "<span class='kit' data-kit='datesInterval' ?? >  ?? </span>"
  • macro definition in config.edn:
    :int "<span class='kit' data-kit='datesInterval' data-dates='$1'>$1</span>"
    
  • code to register the kit, read the dates, calculate the interval, and replace the macro with the result:
    logseq.kits.setStatic(function datesInterval(span){
        const dates = span.dataset.dates;
        const index = dates.indexOf("]], [[");
        const dateStr1 = dates.slice(0, index + 2);
        const dateStr2 = dates.slice(index + 4);
    
        const dateObj1 = convertToDateObject(dateStr1);
        const dateObj2 = convertToDateObject(dateStr2);
    
        const allDates = getAllDatesBetween(dateObj1, dateObj2);
        const formattedDates = allDates.map(date => formatDateToLogseqJournalName(date)).join(" ");
    
        const blockId = span.closest(".ls-block").getAttribute("blockid");
        const content = logseq.api.get_block(blockId).content;
        const macroStart = content.indexOf("{{" + span.closest(".macro").dataset.macroName);
        const macroEnd = content.indexOf("}}", macroStart) + 2;
        logseq.api.update_block(blockId, content.slice(0, macroStart) + formattedDates + content.slice(macroEnd));
    });
    
1 Like

This works wonderfully but I am trying to make a slight modification and it’s driving me crazy as why it’s not working. So, instead of calling it with:

{{int  [[Monday, 13.05.2024]], [[Wednesday, 15.05.2024]] }}

I am trying to make it work with:

{{int  [[Monday, 13.05.2024]] [[Wednesday, 15.05.2024]] }}

so to spare the comma and write less. The code becomes:

[...]
    const index = dates.indexOf("]] [[");
    const dateStr1 = dates.slice(0, index + 2);
    const dateStr2 = dates.slice(index + 3);
[...]

But the macro invoction doesn’t work unless I enclose the dates in quotes…
Why with comma it works without quotes and without the comma it needs quotes to work?

Macros’ parser doesn’t like special characters, so the unexpected thing is that it coincidentally works as much as it does (the invocation should have failed much earlier). Therefore, you should look for any further coincidence, not for logical explanations. Things would be much more sane if you used a simpler date format. I would also think of replacing one of the dates with a number, indicating the length of the interval in days.