My new template idea for Calendar

Something I find useful on occasion is to have a full-year calendar to refer to, so I worked out how to generate an Obsidian note with that information using Templater.

First, I wrote the following javascript file and added it to my Templater scripts folder:

mdCalendar.js

function mdCalendar(year,month,mondayFirst)
{
   if (mondayFirst === undefined) { mondayFirst = false; }
   //Step 1: build an array of the abbreviated weekday names
   let dd = new Date(2022,1,27);  //a Sunday
   let wnames = [];
   for (let i = 0; i < 8; i++)
   {
      wnames.push(dd.toLocaleString('default', { weekday: 'short' }));
      dd.setDate(dd.getDate() + 1);
   }

   if (mondayFirst)
   {
      wnames = wnames.slice(1,8);  //gives [Mon,Tue,Wed,Thu,Fri,Sat,Sun]
   }
   else
   {
      wnames = wnames.slice(0,7);  //gives [Sun,Mon,Tue,Wed,Thu,Fri,Sat]
   }

   //Step 2: Get first day of the month
   // (Note: in the javascript Date object, the month has values from 0[Jan] to 11[Dec].)
   let day = new Date(year,month - 1,1);

   //Step 3: Establish the calendar header which includes the month, year, and abbreviated weekday names
   let cal = `${day.toLocaleString('default', { month: 'long' })} ${year}\n\n`
           + `| ${wnames.join(" | ")} |\n`
           + "|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n"
           ;

   //Step 4: Populate the calendar with the days of the month
   let week = ['  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. '];
   while (day.getMonth() == month - 1)
   {
      let wday = day.getDay();  //day of the week (0[Sun] - 6[Sat])
      if (mondayFirst) { wday = (wday - 1 < 0) ? 6 : wday - 1; }
      let d = `${day.getDate()}`;
      week[wday] = '  ' + d.padStart(2,'0') + ' ';
      if (wday == 6)
      {
         cal += '|' + week.join('|') + '|\n';
         week = ['  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. '];
      }
      day = new Date(day.getFullYear(), day.getMonth(), day.getDate() + 1);
   }
   if (week[0] != '  .. ') { cal += '|' + week.join('|') + '|\n'; }

   return cal;
}

module.exports = mdCalendar;

The mdCalendar function requires two pieces of information: the 4-digit year and the month number (1-12). An optional third parameter determines whether the week starts on Monday (true) or on Sunday (false). If this parameter is omitted, the calendar starts on Sunday. From these parameters, it generates a Markdown table for that month’s calendar. For example, calling mdCalendar(2022,6,true) will return:

June 2022

| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|  .. |  .. |  01 |  02 |  03 |  04 |  05 |
|  06 |  07 |  08 |  09 |  10 |  11 |  12 |
|  13 |  14 |  15 |  16 |  17 |  18 |  19 |
|  20 |  21 |  22 |  23 |  24 |  25 |  26 |
|  27 |  28 |  29 |  30 |  .. |  .. |  .. |

Note 1:
The month name and the weekday abbreviations come from the machine’s localization settings. Presumably, therefore, if you ran this on a system other than an English one, it should output content in the local language. I don’t have a way to verify this.

Note 2:
To turn the days into links, you’d need to modify the line week[wday] = ' ' + d.padStart(2,'0') + ' '; to match the format you use to name day notes. For example, if you use the format YYYY-MM-DD to name your notes, try something like:

week[wday] = '  [[' + day.toISOString().slice(0, 10) + '|' + d.padStart(2,'0') + ']] ';

Second, I put together the following template and added it to my Templater templates folder:

insert-year-calendar.md

<%*
   let year = await tp.system.prompt("Year of Calendar",tp.date.now("YYYY"));
   let firstd = await tp.system.suggester(["Sunday","Monday"],["Sunday","Monday"],false,"First Day of the Week");

   let monFirst = false;
   if (firstd == "Monday") { monFirst = true; }

   if (tp.file.title.startsWith("Untitled"))
   {
      await tp.file.rename(`${year}.calendar`);
   }

   tR += `# ${year} Calendar\n\n`
   for (let i = 1; i <= 12; i++)
   {
      tR += `## ${tp.user.mdCalendar(year,i,monFirst)}\n\n`;
   }
%>

Opening a new note and then running this template through Templater will prompt you to enter the desired year (defaulting to the current one) and to pick which day starts the week. From that it will populate the note with the month calendars for the entire year. On my Obsidian instance it looks like this (in edit mode) when it’s done:

I hope this helps get you to what you need.

4 Likes

Hi @ninjineer ,

I am very happy with your code & template, thanks!

When I stick to just that, all works beautifully. But my reason to want a calendar like this is for making it link to my daily notes. So I tried your suggestion of replacing

      week[wday] = '  ' + d.padStart(2,'0') + ' ';

with

week[wday] = '  [[' + day.toISOString().slice(0,10) + '|' + d.padStart(2,'0') + ']] ';

but that doesn’t quite work in my situation.

It parses this:

## januari 2022

| ma | di | wo | do | vr | za | zo |
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|  .. |  .. |  .. |  .. |  .. |  [[2021-12-31|01]] |  [[2022-01-01|02]] |
|  [[2022-01-02|03]] |  [[2022-01-03|04]] |  [[2022-01-04|05]] |  [[2022-01-05|06]] |  [[2022-01-06|07]] |  [[2022-01-07|08]] |  [[2022-01-08|09]] |
|  [[2022-01-09|10]] |  [[2022-01-10|11]] |  [[2022-01-11|12]] |  [[2022-01-12|13]] |  [[2022-01-13|14]] |  [[2022-01-14|15]] |  [[2022-01-15|16]] |
|  [[2022-01-16|17]] |  [[2022-01-17|18]] |  [[2022-01-18|19]] |  [[2022-01-19|20]] |  [[2022-01-20|21]] |  [[2022-01-21|22]] |  [[2022-01-22|23]] |
|  [[2022-01-23|24]] |  [[2022-01-24|25]] |  [[2022-01-25|26]] |  [[2022-01-26|27]] |  [[2022-01-27|28]] |  [[2022-01-28|29]] |  [[2022-01-29|30]] |
|  [[2022-01-30|31]] |  .. |  .. |  .. |  .. |  .. |  .. |

which looks like this in preview mode

januari 2022

ma di wo do vr za zo
[[2021-12-31 01]]
[[2022-01-02 03]] [[2022-01-03 04]] [[2022-01-04 05]] [[2022-01-05
[[2022-01-09 10]] [[2022-01-10 11]] [[2022-01-11 12]] [[2022-01-12
[[2022-01-16 17]] [[2022-01-17 18]] [[2022-01-18 19]] [[2022-01-19
[[2022-01-23 24]] [[2022-01-24 25]] [[2022-01-25 26]] [[2022-01-26
[[2022-01-30 31]]

I had a different naming format for my dailynotes, so I figured it was that, and delete all my daily notes, changed the naming back to YYYY-MM-DD as per your example, created some daily notes and tried again. But it doesn’t make a difference. It still gets parsed like I’ve shown you above.

Then I remembered you need to escape a | inside an Obsidian Markup table with a \ - and found out that in javascript, I even need to escape it with double \. So I replaced your line with this:

      week[wday] = '  [[' + day.toISOString().slice(0,10) + '\\|' + d.padStart(2,'0') + ']] ';

Now the tables do parse right…linked and all…BUT every single date links to the day before!!

What do I need to change to make the days link to the right Daily Notes?

1 Like

@ninjineer I have had some help over at the Discord channel, and

      week[wday] = `[[${momentDay.format("YYYY-MM-DD")}\\|${momentDay.format("DD")}]]`;

makes the days link to the right daily note and it parses beautifully.

I will include the working script just in case you want to look at it.

mdCalendar.js

function mdCalendar(year,month,mondayFirst)
{
   if (mondayFirst === undefined) { mondayFirst = false; }
   //Step 1: build an array of the abbreviated weekday names
   let dd = new Date(2022,1,27);  //a Sunday
   let wnames = [];
   for (let i = 0; i < 8; i++)
   {
      wnames.push(dd.toLocaleString('default', { weekday: 'short' }));
      dd.setDate(dd.getDate() + 1);
   }

   if (mondayFirst)
   {
      wnames = wnames.slice(1,8);  //gives [Mon,Tue,Wed,Thu,Fri,Sat,Sun]
   }
   else
   {
      wnames = wnames.slice(0,7);  //gives [Sun,Mon,Tue,Wed,Thu,Fri,Sat]
   }

   //Step 2: Get first day of the month
   // (Note: in the javascript Date object, the month has values from 0[Jan] to 11[Dec].)
   let day = new Date(year,month - 1,1);

   //Step 3: Establish the calendar header which includes the month, year, and abbreviated weekday names
   let cal = `${day.toLocaleString('default', { month: 'long' })} ${year}\n\n`
           + `| ${wnames.join(" | ")} |\n`
           + "|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n"
           ;

   //Step 4: Populate the calendar with the days of the month
   let week = ['  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. '];
   while (day.getMonth() == month - 1)
   {
      let wday = day.getDay();  //day of the week (0[Sun] - 6[Sat])
      if (mondayFirst) { wday = (wday - 1 < 0) ? 6 : wday - 1; }
      let d = `${day.getDate()}`;
      //week[wday] = '  ' + d.padStart(2,'0') + ' ';
      //week[wday] = '  [[' + day.toISOString().slice(0,10) + '\\|' + d.padStart(2,'0') + ']] ';
      momentDay = moment(day);
      week[wday] = `[[${momentDay.format("YYYY-MM-DD")}\\|${momentDay.format("DD")}]]`;

      if (wday == 6)
      {
         cal += '|' + week.join('|') + '|\n';
         week = ['  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. '];
      }
      day = new Date(day.getFullYear(), day.getMonth(), day.getDate() + 1);
   }
   if (week[0] != '  .. ') { cal += '|' + week.join('|') + '|\n'; }

   return cal;
}

module.exports = mdCalendar;

and the template insert-year-calendar.md

   let year = await tp.system.prompt("Year of Calendar",tp.date.now("YYYY"));
   let firstd = await tp.system.suggester(["Sunday","Monday"],["Sunday","Monday"],false,"First Day of the Week");

   let monFirst = false;
   if (firstd == "Monday") { monFirst = true; }

   if (tp.file.title.startsWith("Untitled"))
   {
      await tp.file.rename(`${year}.calendar`);
   }

   tR += `# ${year} Calendar\n\n`
   for (let i = 1; i <= 12; i++)
   {
      tR += `## ${tp.user.mdCalendar(year,i,monFirst)}\n\n`;
   }
%>
3 Likes

Sorry to have caused difficulty with that line of back-of-the-envelop code. I really should have tested it before tossing it out there. For what it’s worth, I suspect the problem where your dates and day values were showing up off by one (ex: [[2022-01-02|03]]) arose from the toISOString function. Depending on what time zone you’re in, it can shift the date value into the prior day. Using moment to format the dates makes things much easier and straight forward.

2 Likes

Wow, this is phenomenal. I wonder whether it could be easily amended to include the weekly notes (like the Calendar plugin) at the beginning of each week.

1 Like

It probably can be adapted, but I am just someone who comes up with an idea and then try myself first, and usually need help (a lot!) to make it happen what I want :wink: - and I second your idea, would love the weeknumbers to be included and linked to the weekly notes. Perhaps even the months and the year, too, to their respective counterparts.

Back in the early days of Obsidian people have made a script like that, they got very far but it was abandoned. I haven’t checked it yet, it might just need a couple of edits for it to work in the present version of Obsidian. The discussion about it, with examples of the script, is here: Calendar and tasks for daily notes - #41 by afv

One that is a bit more recent and might, if further developed, eventually replace everything I have come up with myself. Looks very promising! You can find it here: GitHub - Quorafind/Obsidian-Big-Calendar: Big Calendar in Obsidian, for manage your events in a day/week/month and see agenda too!

@ninjineer and @ScholarInTraining - this is FYI too in case you want to take a look, collaborate, or anything :wink:

1 Like

Still very pleased with your work, @ninjineer ! And it’s working now, so t doesn’t matter who made that happen. Obsidian is all about community and helping each other, isn’t it:)

1 Like

Ok, I’ve nearly got it. This code seems to produce the desired layout for me, but it gets formatted incorrectly in the last week of each month (and the first week of the year). Would love some help from anyone who could fix that part.

function mdCalendar(year,month,mondayFirst)
{
   if (mondayFirst === undefined) { mondayFirst = false; }
   //Step 1: build an array of the abbreviated weekday names
   let dd = new Date(2022,1,27);  //a Sunday
   let wnames = [];
   for (let i = 0; i < 8; i++)
   {
      wnames.push(dd.toLocaleString('default', { weekday: 'short' }));
      dd.setDate(dd.getDate() + 1);
   }

   if (mondayFirst)
   {
      wnames = wnames.slice(1,8);  //gives [Mon,Tue,Wed,Thu,Fri,Sat,Sun]
   }
   else
   {
      wnames = wnames.slice(0,7);  //gives [Sun,Mon,Tue,Wed,Thu,Fri,Sat]
   }

   //Step 2: Get first day of the month
   // (Note: in the javascript Date object, the month has values from 0[Jan] to 11[Dec].)
   let day = new Date(year,month - 1,1);

   //Step 3: Establish the calendar header which includes the month, year, and abbreviated weekday names
   let cal = `${day.toLocaleString('default', { month: 'long' })} ${year}\n\n`
           + `| Week | ${wnames.join(" | ")} |\n`
           + "|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n"
           ;

   //Step 4: Populate the calendar with the days of the month
   let week = ['  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. '];
   while (day.getMonth() == month - 1)
   {
      let wday = day.getDay();  //day of the week (0[Sun] - 6[Sat])
      momentDay = moment(day);
      if (mondayFirst) { wday = (wday - 1 < 0) ? 6 : wday - 1; }
      if (wday == 1){
            cal+= '|' + `[[${momentDay.format("gggg-[W]WW")}\\|${momentDay.format("WW")}]]` ;
      }
      let d = `${day.getDate()}`;
      //week[wday] = '  ' + d.padStart(2,'0') + ' ';
      //week[wday] = '  [[' + day.toISOString().slice(0,10) + '\\|' + d.padStart(2,'0') + ']] ';
      
      week[wday] = `[[${momentDay.format("YYYY-MM-DD")}\\|${momentDay.format("DD")}]]`;

      if (wday == 6)
      {
         cal += '|' + week.join('|') + '|\n';
         week = ['  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. '];
      }
      day = new Date(day.getFullYear(), day.getMonth(), day.getDate() + 1);
   }
   if (week[0] != '  .. ') { cal += '|' + week.join('|') + '|\n'; }

   return cal;
}

module.exports = mdCalendar;

1 Like

Closer still, but still messes up in the first week of most months (leaving off the last day of the month if it’s a Monday, shifting the days of the week if the first days of the month aren’t a Monday)

function mdCalendar(year,month,mondayFirst)
{
   if (mondayFirst === undefined) { mondayFirst = false; }
   //Step 1: build an array of the abbreviated weekday names
   let dd = new Date(2022,1,27);  //a Sunday
   let wnames = [];
   for (let i = 0; i < 8; i++)
   {
      wnames.push(dd.toLocaleString('default', { weekday: 'short' }));
      dd.setDate(dd.getDate() + 1);
   }

   if (mondayFirst)
   {
      wnames = wnames.slice(1,8);  //gives [Mon,Tue,Wed,Thu,Fri,Sat,Sun]
   }
   else
   {
      wnames = wnames.slice(0,7);  //gives [Sun,Mon,Tue,Wed,Thu,Fri,Sat]
   }

   //Step 2: Get first day of the month
   // (Note: in the javascript Date object, the month has values from 0[Jan] to 11[Dec].)
   let day = new Date(year,month - 1,1);

   //Step 3: Establish the calendar header which includes the month, year, and abbreviated weekday names
   let cal = `${day.toLocaleString('default', { month: 'long' })} ${year}\n\n`
           + `| Week | ${wnames.join(" | ")} |\n`
           + "|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n"
           ;

   //Step 4: Populate the calendar with the days of the month
   let week = ['  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. '];
   while (day.getMonth() == month - 1)
   {
      let wday = day.getDay();  //day of the week (0[Sun] - 6[Sat])
      momentDay = moment(day);
      if (mondayFirst) { wday = (wday - 1 < 0) ? 6 : wday - 1; }
      if (wday == 1){
            cal+= '|' + `[[${momentDay.format("gggg-[W]WW")}\\|${momentDay.format("WW")}]]` ;
      }
      let d = `${day.getDate()}`;
      //week[wday] = '  ' + d.padStart(2,'0') + ' ';
      //week[wday] = '  [[' + day.toISOString().slice(0,10) + '\\|' + d.padStart(2,'0') + ']] ';
      
      week[wday] = `[[${momentDay.format("YYYY-MM-DD")}\\|${momentDay.format("DD")}]]`;

      if (wday == 6)
      {
         cal += '|' + week.join('|') + '|\n';
         week = ['  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. '];
      }
      day = new Date(day.getFullYear(), day.getMonth(), day.getDate() + 1);
   }
   if (week[1] != '  .. ') { cal += '|' + week.join('|') + '|\n'; }

   return cal;
}

module.exports = mdCalendar;

@scholarInTraining can you shine your brainlight on this for @derekvan ? And also Derek, the Obsidianers at the Discord channels are usually very helpful too!

@FiekeB Ow, datetime math makes my brain hurt! Can you answer for me what the week number should point to 2022-01-01, which was a Saturday? Does week 1 start on 2022-01-03 for you?

Things that aren’t wrong hidden, thanks for the correction @ninjineer !

Hidden

Never mind, this seems fine. @derekvan Are you sure this works at the end of months? Is January 32nd re-interpreted as Feb 1?

@derekvan uhh… typo here? 2022-01-27 is a Thursday?

I would have expected this to be on 0, since you just rotated your weekdays in the line above? I think that would fix your end of the month output above. Similarly, should the if statement right before the return really be checking for 1?
EDIT: Also I don’t see how this produces a week number for the first week of a month, unless the first day of the month is the first day of a week. I think you may need to special-case the first day of the month?

With JavaScript Date objects, the months are zero-based (i.e. 0=January, 1=February, etc.). Thus new Date(2022,1,27) corresponds to February 27, 2022.

1 Like

@ninjaneer @derekvan @FiekeB
It looks like moment’s Moment.weekday field respects locale and might help get rid of some of the extra logic?

Yeah, I’m not really sure how this is working so I’m just sort of trial and erroring my way through. The code without the week column works perfectly well, so I wasn’t really trying to monkey with any of the date logic, just figure out a way to bolt on an extra column without disrupting anything else. Haven’t been able to achieve that quite yet. At any rate, changing it to wday==0 doesn’t work either–it produces a different result but the dates in the first and last weeks are still shifted weird.

Trial-and-error indeed! Can you see if:

        if (day.getDate() === 1 || wday === 0) {
            cal += "|" + `[[${momentDay.format("gggg-[W]WW")}\\|${momentDay.format("WW")}]]`;
        }

works as a replacement for the insertion of the week link? Since we always want to make sure a week link has been placed for the first day of the month? (Javascript seems to believe in triple equals instead of double equals for equality checks, still understanding why.)

EDIT: This SHOULD fix the first week of the month. I have no idea still about the issue for the last week of the month.

2 Likes

hot dog! that did it. Thanks a million. (somehow it fixed both the first and last weeks (also I reset another change I had made at the end of the script which I think helped).

Final script for those following along at home:

function mdCalendar(year,month,mondayFirst)
{
   if (mondayFirst === undefined) { mondayFirst = false; }
   //Step 1: build an array of the abbreviated weekday names
   let dd = new Date(2022,1,27);  //a Sunday
   let wnames = [];
   for (let i = 0; i < 8; i++)
   {
      wnames.push(dd.toLocaleString('default', { weekday: 'short' }));
      dd.setDate(dd.getDate() + 1);
   }

   if (mondayFirst)
   {
      wnames = wnames.slice(1,8);  //gives [Mon,Tue,Wed,Thu,Fri,Sat,Sun]
   }
   else
   {
      wnames = wnames.slice(0,7);  //gives [Sun,Mon,Tue,Wed,Thu,Fri,Sat]
   }

   //Step 2: Get first day of the month
   // (Note: in the javascript Date object, the month has values from 0[Jan] to 11[Dec].)
   let day = new Date(year,month - 1,1);

   //Step 3: Establish the calendar header which includes the month, year, and abbreviated weekday names
   let cal = `${day.toLocaleString('default', { month: 'long' })} ${year}\n\n`
           + `| Week | ${wnames.join(" | ")} |\n`
           + "|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n"
           ;

   //Step 4: Populate the calendar with the days of the month
   let week = ['  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. '];
   while (day.getMonth() == month - 1)
   {
      let wday = day.getDay();  //day of the week (0[Sun] - 6[Sat])
      momentDay = moment(day);
      if (mondayFirst) { wday = (wday - 1 < 0) ? 6 : wday - 1; }
      if (day.getDate() === 1 || wday === 0) {
         cal += "|" + `[[${momentDay.format("gggg-[W]WW")}\\|${momentDay.format("WW")}]]`;
     }
      let d = `${day.getDate()}`;
      //week[wday] = '  ' + d.padStart(2,'0') + ' ';
      //week[wday] = '  [[' + day.toISOString().slice(0,10) + '\\|' + d.padStart(2,'0') + ']] ';
      
      week[wday] = `[[${momentDay.format("YYYY-MM-DD")}\\|${momentDay.format("DD")}]]`;

      if (wday == 6)
      {
         cal += '|' + week.join('|') + '|\n';
         week = ['  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. '];
      }
      day = new Date(day.getFullYear(), day.getMonth(), day.getDate() + 1);
   }
   if (week[0] != '  .. ') { cal += '|' + week.join('|') + '|\n'; }

   return cal;
}

module.exports = mdCalendar;
3 Likes

For what it’s worth, I created a second function, based on my original calendar generator, that prepends each calendar line with the week number of the year. It produces output like this:

January 2022

| [W#] | Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|:----:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| [52] |  .. |  .. |  .. |  .. |  .. |  .. |  01 |
| [01] |  02 |  03 |  04 |  05 |  06 |  07 |  08 |
| [02] |  09 |  10 |  11 |  12 |  13 |  14 |  15 |
| [03] |  16 |  17 |  18 |  19 |  20 |  21 |  22 |
| [04] |  23 |  24 |  25 |  26 |  27 |  28 |  29 |
| [05] |  30 |  31 |  .. |  .. |  .. |  .. |  .. |

Note 1: I enclosed the week numbers in square brackets to visually distinguish them from the day numbers in the calendar.

Note 2: I titled the week number column [W#]. I did not use [Week] because that would not mesh with the localization of the month and day names. I did not use [#] because it did not seem obvious to me what just a raw number was supposed to represent. [W#] seemed like a reasonable compromise, but I’m still not entirely thrilled with it.

Note 3: I’ll leave it as an exercise to the reader to determine how best to turn those week numbers into links, as that will depend entirely on how you define such notes.

Here’s the new function:

 function mdCalendarWithWeekNum(year,month,mondayFirst)
 {
    if (mondayFirst === undefined) { mondayFirst = false; }

    //Step 1: build an array of the abbreviated weekday names
    let dd = new Date(2022,1,27);  //a Sunday
    let wnames = [];
    for (let i = 0; i < 8; i++)
    {
       wnames.push(dd.toLocaleString('default', { weekday: 'short' }));
       dd.setDate(dd.getDate() + 1);
    }

    if (mondayFirst)
    {
       wnames = wnames.slice(1,8);  //gives [Mon,Tue,Wed,Thu,Fri,Sat,Sun]
    }
    else
    {
       wnames = wnames.slice(0,7);  //gives [Sun,Mon,Tue,Wed,Thu,Fri,Sat]
    }

    //Step 2: Get first day of the month
    // (Note: in the javascript Date object, the month has values from 0[Jan] to 11[Dec].)
    let day = new Date(year,month - 1,1);

    //Step 3: Establish the calendar header which includes the month, year, and abbreviated weekday names

    let cal = `${day.toLocaleString('default', { month: 'long' })} ${year}\n\n`
            + `| [W#] | ${wnames.join(" | ")} |\n`
            + "|:----:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n"
            ;

    //Step 4: Define a function to calculate the week number of the year
    const weekOfYear = (adate,mondayFirst) => {
      let firstWeekStart = new Date(adate.getFullYear(),0,1);
      let offset = 0;
      if (mondayFirst) { offset = 1};
      let day = firstWeekStart.getDay() - offset;
      if (day < 0) day = 6;
      let daysUntilWeekStart = day !== 0 ? 7 - day : 0;
      firstWeekStart.setDate(firstWeekStart.getDate() + daysUntilWeekStart);
      return (Math.floor((adate - firstWeekStart)/(24 * 60 * 60 * 1000) / 7) + 1);
   }

    //Step 5: Populate the calendar with the days of the month
    let week = ['  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. '];
    let wnum = '0';
    while (day.getMonth() == month - 1)
    {
       wnum = `${weekOfYear(day,mondayFirst)}`;
       if (wnum == '0') { wnum = '52'; }
       let wday = day.getDay();  //day of the week (0[Sun] - 6[Sat])
       if (mondayFirst) { wday = (wday - 1 < 0) ? 6 : wday - 1; }
       let d = `${day.getDate()}`;
       week[wday] = '  ' + d.padStart(2,'0') + ' ';
       if (wday == 6)
       {
          cal += '| [' + wnum.padStart(2,'0') + '] |' + week.join('|') + '|\n';
          week = ['  .. ','  .. ','  .. ','  .. ','  .. ','  .. ','  .. '];
       }
       day = new Date(day.getFullYear(), day.getMonth(), day.getDate() + 1);
    }

    if (week[0] != '  .. ') { cal += '| [' + wnum.padStart(2,'0') + '] |' + week.join('|') + '|\n'; }

    return cal;
 }
2 Likes

Overhere, we just use WK or wk as abbr form of week…is that an idea instead of W# (I HATE hastags haha)

And I wonder, is there a possibility to distinguish the weekdays and the weeknumbers in bold? That would set them both apart from the wholefield with the day numbers.

I love this “multiple minds know more” attitude of the Obsidian Community! Well done peepz! :heart: @ninjineer , @scholarInTraining and @derekvan !!

1 Like

I like idea of using WK. If I was serious about leaving it up to the user to define what works for them, I’d make the label a variable that gets passed into the function. Then in the Templater template, I could prompt for the value.

Sure you could apply bolding on the week numbers. Just replace the [ and ] characters with **. (Or put the ** before and after those characters if you want to keep the square brackets.) I live the edit mode with a monospaced font, so my preference tends towards formatting that looks at home in that environment.

1 Like