Skip to content

Instantly share code, notes, and snippets.

@bene-we
Last active May 3, 2024 13:23
Show Gist options
  • Save bene-we/e0a306ad6788fec5dbe45cde2de2f140 to your computer and use it in GitHub Desktop.
Save bene-we/e0a306ad6788fec5dbe45cde2de2f140 to your computer and use it in GitHub Desktop.
Calculate the age of a person and write it to the event's description in your birthday calendar using Google Apps Script

Calculate the age of a person and write it to the event's description in your birthday calendar using Google Apps Script

This script uses Google Apps Script to access one's Google Calendar and calculate the age on a person's birthday. In the best case you have a custom calendar where your birthdays are stored at. If not, uncomment line 20 and use the filter function at the bottom.

Steps to setup everything

  1. Head to https://script.google.com/home/my and create a new project. Rename the existing file Code.gs to your liking and paste the code from calculateAge.gs.
  2. Paste your calendar ID in line 9 (you can find it in the Google Calendar Settings)
  3. Make sure to add the birth year of a person to the location field (or customize the script)
  4. Customize the message in line 36
  5. Hit run and see the messages appear in your calendar events for the current year!
  6. Create a trigger to run this every year to calculate the correct age

const TAG_NAME = 'calculatedAge';
const FORCE_OVERWRITE = false;
/*
* Calculate the age of the birthday people in each year and write it in the description
*/
function calculateAge() {
// Get Calendar 'Birthdays'
var birthdayCal = CalendarApp.getCalendarById("calendarIdGoesHere");
// Select date range of current year
var currentYear = (new Date()).getFullYear();
var start = new Date(currentYear + '-01-01');
var end = new Date(currentYear + '-12-31');
// Fetch events from Birthday Calendar
var birthdays = birthdayCal.getEvents(start, end);
// Filter Birthdays out of Default Calendar (if no specific Birthday Calendar is present)
// birthdays = birthdays.filter(filterBirthdays);
var calculatedAge;
for (var i = 0; i < birthdays.length; i++) {
e = birthdays[i];
// Year of birth is stored in the Location field of the event
if (e.getLocation() !== "") {
// Calculate the age if it has not been done before OR FORCE_OVERWRITE is true
if ((e.getDescription() === "" && isNaN(parseInt(e.getTag(TAG_NAME)))) || FORCE_OVERWRITE) {
calculatedAge = Math.round(currentYear - parseInt(e.getLocation()));
// Customize the description here
e.setDescription(e.getTitle() + ' wird heute ' + calculatedAge + ' Jahre!');
// Save calculated age in tag
e.setTag(TAG_NAME, calculatedAge);
// Logger.log(e.getTitle(), ' | ', e.getTag(TAG_NAME), ' | ', e.getDescription());
}
}
}
}
/*
* Filter the birthdays out of the fetched events
* Add additional filters if you don't have a specific Birthday Calendar
*/
function filterBirthdays(event) {
// Add filter here (e.g. event.getColor === CalendarApp.Color.YELLOW)
return event.isAllDayEvent();
}
@bene-we
Copy link
Author

bene-we commented Aug 10, 2020

@greenssd Glad you got it to work!

@ThowZzy
Copy link

ThowZzy commented Aug 3, 2022

Cheers !
I created a function that calls the main function twice but with a year+1 so its even more updated

@bene-we
Copy link
Author

bene-we commented Aug 8, 2022

@ThowZzy nice idea! I'm going to update this as well :)

@AKASGaming
Copy link

Any chance you could add popup reminders to it?

@Endelos
Copy link

Endelos commented Sep 25, 2022

Cheers ! I created a function that calls the main function twice but with a year+1 so its even more updated

Would you share it ? Or even a function that would do the job for the next 20 or 30 years with a for loop ? I would really appreciate it !
I would write it if I had the time to learn this language, unfortunately I don't have this luxury...

@bene-we
Copy link
Author

bene-we commented Sep 26, 2022

Any chance you could add popup reminders to it?

@AKASGaming I went to Google Calender Settings, selected the specific calendar and added default reminders to it, works great!

image

@ThowZzy
Copy link

ThowZzy commented Sep 26, 2022

Cheers ! I created a function that calls the main function twice but with a year+1 so its even more updated

Would you share it ? Or even a function that would do the job for the next 20 or 30 years with a for loop ? I would really appreciate it ! I would write it if I had the time to learn this language, unfortunately I don't have this luxury...

I just did this:

.....
function calculateAge_2_year(){
  calculateAge(0);
  calculateAge(1);
}

/*
 * Calculate the age of the birthday people in each year and write it in the description
 */
function calculateAge(year_added=0) {
  // Get Calendar 'Birthdays'
  var birthdayCal = CalendarApp.getCalendarById("");
  
  // Select date range of current year
  var currentYear = (new Date()).getFullYear()+year_added;
  .....

And then you just need to create a task to execute this new "calculatedAge_2_year" function instead of the "CalculateAge" one.

And to do for like 30 years you could do this:

function calculateAge_30_years(){
  for(var year_add=0; year_add<=30; year_add++){
       calculateAge(year_add); 
    }
}

@Endelos
Copy link

Endelos commented Sep 28, 2022

I just did this: [...]

Oh I see, really simple indeed ! Thanks a lot, it works great !

@ruifchaves
Copy link

ruifchaves commented Jan 8, 2023

Any chance you could add popup reminders to it?

@AKASGaming I went to Google Calender Settings, selected the specific calendar and added default reminders to it, works great!

image

First of all, thanks for sharing the code! It has been really helpful!

I never got the reminders to work properly so I did some experiments. I tried to get the all-day default notifications to be assigned to a new calendar event and it does work. The problem is that when executing the script (specifically when setting the description - e.setDescription()) the reminders/notifications are deleted!! I tried checking if each event was in fact an all day event (isAllDayEvent()), then I tried e.removeAllReminders() followed by e.resetRemindersToDefault(). What this did was applying the non all-day default notifications to the event (in spite of being an all day event) and deleting the previous ones set when creating the event.

Later I tested the effects of the scripts when setting different defaults to different times:

reminders_prev_run
reminders_pos_run

I wondered if it was the API that was creating a new event and deleting the previous one whenever the Description of the event is set, meaning that the other event metadata would be copied using its own API(????), meaning that it would abide to the restrictions of the api itself (addPopupReminder() -> must be at least 5 minutes before the event) but in this case the midnight reminder would be deleted!!!

In conclusion, it seems that every all-day default reminder/notification set to the actual day of the event is removed (except for the one at midnight) and only the ones set to prior of the day of the event are kept. I couldn't find anything that could lead to this problem.
Do you think this is a bug? Do you think there's a workaround?

EDIT:
-It seems that running the script is locking the ability to edit notification time! When I try to change the notification parameters of an all day event that repeats yearly it doesn't save, despite giving that feedback. All other parameters (title, description, date and time, visibility, etc) are changeable and the changes saved. Non all day and events that don't repeat, do repeat and all day events that don't repeat are not affected, meaning that we can edit every parameter of the event after running the script.
-Another weird thing: whenever I try to change the notification time of a problematic event (event subject to the script's changes) it does not get saved but changing the events date to any other date, makes the supposed unsaved changes appear!
Example:
1- create an all day yearly event with location 2020, a default all day notification of 00:00, at date 24/03/2023
2- run the script
3- description of the event now has changed to "its rachels 30th birthday" and still has the 00 notification
4- I change notification to 00:50 and save
5- IT DOES NOT GET SAVED appearing as follow:
1111
6- change the event date to 25/03/2023
7- IT APPEARS WITH CORRECT NOTIFICATION TIME!!??? as follow:
2222
8- change it back to day 24/03 -> notification time changes back to 00:00!!!!?
9- change the event to 2 days 24/03 to 25/03 -> notification time stays at 00:00!!!!?

@jcb782
Copy link

jcb782 commented Jan 17, 2023

I never got the reminders to work properly so I did some experiments. I tried to get the all-day default notifications to be assigned to a new calendar event and it does work. The problem is that when executing the script (specifically when setting the description - e.setDescription()) the reminders/notifications are deleted!! I tried checking if each event was in fact an all day event (isAllDayEvent()), then I tried e.removeAllReminders() followed by e.resetRemindersToDefault(). What this did was applying the non all-day default notifications to the event (in spite of being an all day event) and deleting the previous ones set when creating the event.

I had the same problem. Every time I ran the script, the time disappeared, except I wasn't ever able to get the default setting when switching dates. Like you, I also tried e.resetRemindersToDefault(), but that didn't seem to work. in my testing, I was able to get e.addPopupReminder(minutesBefore) to work though.

Instead of calculating the minutes by hand, I entered Logger.log("Reminder Settings: "+ e.getEmailReminders()); before the script checked the description (line 31) to figure out how many minutes was set by default. Then I adjusted minutesBefore to that number.

Hope that helps for you.

@ruifchaves
Copy link

For some reason I can't recall right now, I really wanted the all day event notification to be the one set as the default so the addPopupReminder command wasn't a solution for me. Thank you for the suggestion tho!
Making use of the Logger is indeed very helpful. I also used it to debug the script one by one! I ended up setting a default all day reminder to 0 days before at 00:00 and deleted and added all the events and ran the script. This way the reminder isn't deleted by the script and goes off at midnight. Good enough :)

@dribnus
Copy link

dribnus commented Mar 26, 2024

I'm not good with understanding scripts in detail. I was able to use the first script with no issues. I really like the ideas and examples that followed, but I couldn't figure out how to add those functions into the original script. Basically I would like to see the "age" data for the next 3 years for the birthdays. Can someone break it down for the stupid one as to how the whole script would look? Thank you.

@Beeger
Copy link

Beeger commented May 2, 2024

I can't get the original script to work, can someone help me find out what's wrong? It also seems like the debugging breakpoints nor logging work so I can't see what's happening on the inside:

image

The log just says it ran successfully but the calendar event didn't change.

function myFunction() {
  const TAG_NAME = 'calculatedAge';
const FORCE_OVERWRITE = false;

/*
 * Calculate the age of the birthday people in each year and write it in the description
 */
function calculateAge() {
  // Get Calendar 'Birthdays'
  var birthdayCal = CalendarApp.getCalendarById("35fcc071468e5458ae9260955551cdc7f91d06ec3b22c665c71c9e512d50e643@group.calendar.google.com");
  
  // Select date range of current year
  var currentYear = (new Date()).getFullYear();
  var start = new Date(currentYear + '-01-01');
  var end = new Date(currentYear + '-12-31');
  
  // Fetch events from Birthday Calendar
  var birthdays = birthdayCal.getEvents(start, end);
  
  // Filter Birthdays out of Default Calendar (if no specific Birthday Calendar is present)
  // birthdays = birthdays.filter(filterBirthdays);
  
  var calculatedAge;
  
  for (var i = 0; i < birthdays.length; i++) {
    e = birthdays[i];
    
    // Year of birth is stored in the Location field of the event
    if (e.getLocation() !== "") {
      
      // Calculate the age if it has not been done before OR FORCE_OVERWRITE is true
      if ((e.getDescription() === "" && isNaN(parseInt(e.getTag(TAG_NAME)))) || FORCE_OVERWRITE) {
        
        calculatedAge = Math.round(currentYear - parseInt(e.getLocation()));
        
        // Customize the description here
        e.setDescription(e.getTitle() + ' wird heute ' + calculatedAge + ' Jahre!');
        
        // Save calculated age in tag
        e.setTag(TAG_NAME, calculatedAge);
        
        // Logger.log(e.getTitle(), ' | ', e.getTag(TAG_NAME), ' | ', e.getDescription());
        
      }
    }    
  }  
}

/*
 * Filter the birthdays out of the fetched events
 * Add additional filters if you don't have a specific Birthday Calendar
 */
function filterBirthdays(event) {
  // Add filter here (e.g. event.getColor === CalendarApp.Color.YELLOW)
  return event.isAllDayEvent();
}
}

@bene-we
Copy link
Author

bene-we commented May 3, 2024

@ruifchaves sorry for getting back to you this late. You really put some effort into this, didn't you! I think I never experienced this issue myself since I've set default reminders on the previous day, and so far I didn't have problems with pop-up reminders. Yet it sounds really buggy what you've experienced, I just don't have an idea what to do about it

@dribnus
Copy link

dribnus commented May 3, 2024

Thank you

@bene-we
Copy link
Author

bene-we commented May 3, 2024

@Beeger just an idea from my side, I've seen that you wrapped the script with myFunction, are you sure that you call that function somewhere? I just tested my version and logs are working correctly, but they only show up if the code actually runs.

Apart from that, I cannot see the full calendar event so I cannot see anything wrong, and second it shouldn't be a big deal but I would try to hide personal details like the calendarId when posting on the internet.

@bene-we
Copy link
Author

bene-we commented May 3, 2024

Thank you

No worries! Let me know if you get it to work! Apart from that, nothing dumb about not being experienced in a topic yet, keep it up 🥳

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment