0

It's a messy code but I've been working on a simple webpage that takes in a standardised format of string, which is a series of dates and a three letter code. I'm trying to create a single ics download file that adds each of these dates as individual full day events.

However, when I open the ics file it opens the calendar as normal but doesn't add any events. No errors anywhere.

The format of the dates that are entered into the text area look something like this:

Wed, 25 Jan 2023 ANI
Thu, 26 Jan 2023 ANI
Fri, 27 Jan 2023 ANI

the created iCal file in text looks similar to this:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//bobbin v0.1//NONSGML iCal Writer//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
BEGIN:VEVENT
DTSTART:2023-01-30T00:00:00.000Z
DTEND:2023-01-30T23:59:59.999Z
DTSTAMP:2023-01-30T00:00:00.000Z
UID:0.78724cf20a484
CREATED:2022-12-30T22:08:08.107Z
DESCRIPTION:INI
SUMMARY:INI
END:VEVENT
BEGIN:VEVENT
DTSTART:2023-01-31T00:00:00.000Z
DTEND:2023-01-31T23:59:59.999Z
DTSTAMP:2023-01-31T00:00:00.000Z
UID:0.aa5407ba9b303
CREATED:2022-12-30T22:08:08.107Z
DESCRIPTION:INI
SUMMARY:INI
END:VEVENT
END:VCALENDAR

Here's the codebase:

function getStartDateString(str) {
  const arr = str.split(', ');
  const month = arr[1].split(' ')[1];
  const monthNum = new Date(`${month} 1, 2022`).getMonth() + 1;
  const dayOfMonth = arr[1].split(' ')[0];
  const year = arr[1].split(' ')[2];
  const date = `${year}-${monthNum}-${dayOfMonth}`;
  const dateObj = new Date(date);

  return dateObj.toISOString();
}

function getEndDateString(str) {
  const arr = str.split(', ');
  const month = arr[1].split(' ')[1];
  const monthNum = new Date(`${month} 1, 2022`).getMonth() + 1;
  const dayOfMonth = arr[1].split(' ')[0];
  const year = arr[1].split(' ')[2];
  const date = `${year}-${monthNum}-${dayOfMonth}`;
  const dateObj = new Date(date);
  dateObj.setHours(23, 59, 59, 999);

  return dateObj.toISOString();
}

function createRandomICalUid() {
  const randomNumber = Math.random();
  const hexString = randomNumber.toString(16);
  const uid = `${hexString}`;

  return uid;
}

function downloadICal() {
  const emailText = document.getElementById("rawRoster").value.split('\n')
  const roster = emailText.filter(line => line.match(/^\w{3}, \d{2} \w{3} \d{4}/));
  
  let rosterDays = '' 
  roster.forEach(day => {
    const Startdate = getStartDateString(day);
    const startDateObj = new Date(Startdate);
    const endDate = getEndDateString(day);
    const endDateObj = new Date(endDate);
    const dtstamp = startDateObj.toISOString();
    const dtend = endDateObj.toISOString();

    let iCalEvent = `BEGIN:VEVENT
DTSTAMP:${dtstamp}
DTSTART:${dtstamp}
DTEND:${dtend}
UID:${createRandomICalUid()}
CREATED:${new Date().toISOString()}
DESCRIPTION:${day.slice(-3)}
SUMMARY:${day.slice(-3)}
LOCATION:Online
END:VEVENT
`

    rosterDays += iCalEvent
  });

  const icalContent = `BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//bobbin v0.1//NONSGML iCal Writer//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
`+rosterDays+`END:VCALENDAR`

  console.log(icalContent);

  // Create a Blob from the iCalendar content
  const blob = new Blob([icalContent], { type: 'text/calendar;charset=utf-8' });

  // Create a link element to use for the download
  const downloadLink = document.createElement('a');
  downloadLink.download = 'duty.ics';
  downloadLink.href = URL.createObjectURL(blob);
  downloadLink.style.display = 'none';

  // Add the link to the DOM and click it to trigger the download
  document.body.appendChild(downloadLink);
  downloadLink.click();

  // Remove the link from the DOM
  document.body.removeChild(downloadLink);

}

document.getElementById("downloadiCal").addEventListener("click", () => downloadICal())

Tarik
  • 60
  • 1
  • 9
  • Have you looked at the file with a text editor? Does it contain what you expect? – Barmar Dec 30 '22 at 22:27
  • I have. Edited the main question to show what it looks like once created: – Tarik Dec 30 '22 at 22:33
  • 1
    Paste the file into https://icalendar.org/validator.html. It reports several errors because the dates aren't in correct format. – Barmar Dec 30 '22 at 22:36
  • brilliant. thank you. The website says that my dates are invalid date/date-time values. Guess I need to look more into it. – Tarik Dec 30 '22 at 22:38
  • The error message has a link to a page that shows all the valid formats. – Barmar Dec 30 '22 at 22:40
  • thanks looking at that now. i'll try and fix my date formatting functions, see if those solve it, and then post the fix – Tarik Dec 30 '22 at 22:41

1 Answers1

0

So thanks to Barmar I was able to figure out that it was the dateTime formatting. I modified the functions that were doing this. They're below. Now it's time for some thorough refactoring!

function getStartDateString(str) {
  const arr = str.split(', ');
  const month = arr[1].split(' ')[1];
  const monthNum = new Date(`${month} 1, 2022`).getMonth() + 1;
  const dayOfMonth = arr[1].split(' ')[0];
  const year = arr[1].split(' ')[2];
  const date = `${year}-${monthNum}-${dayOfMonth}`;
  const dateObj = new Date(date);

  let output = dateObj.toISOString();
  output = output.slice(0, 10).replace(/-/g, '') + output.slice(10);
  output= output.slice(0, -5) + 'Z';
  return output.replace(/:/g, '');
}

function getEndDateString(str) {
  const arr = str.split(', ');
  const month = arr[1].split(' ')[1];
  const monthNum = new Date(`${month} 1, 2022`).getMonth() + 1;
  const dayOfMonth = arr[1].split(' ')[0];
  const year = arr[1].split(' ')[2];
  const date = `${year}-${monthNum}-${dayOfMonth}`;
  const dateObj = new Date(date);
  dateObj.setHours(23, 59, 59, 999);

  let output = dateObj.toISOString();
  output = output.slice(0, 10).replace(/-/g, '') + output.slice(10);
  output= output.slice(0, -5) + 'Z';
  return output.replace(/:/g, '');
}

Tarik
  • 60
  • 1
  • 9