My new template idea for Calendar

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