Уже много лет я пользуюсь Гугл календарем. Всегда было непонятно, почему в нем не отображается возраст людей из Google Контактов в момент наступления дня рождения, годовщины или других значимых событий.



Когда стал целенаправленно искать ответ на этот вопрос, обнаружил, что запрос на отображение возраста в календаре от гугл довольно популярный и однозначного ответа на него до сих пор нет. Это сподвигло меня создать решение на основе Google Apps Script.


Почему именно гугл скрипты?


Не хотелось использовать какую-то стороннюю платформу или сервис, ведь все мои контакты находятся в адресной книге гугла. Также не хотелось пользоваться приложением или дополнением, которое бы собирало какие либо мои персональные данные для использования в непонятных целях. Нужна была прозрачная работающая структура.


Где код?


Не могу сказать что скрипт написан с нуля — я воспользовался наработками Bryan Patterson, которые были опубликованы аж 6 лет назад, в 2014 году.


Вот получившийся результат:


Birthdays and anniversaries with dates for your calendar.gs
// Глобальные переменные
var contactsCal;
var defaultCal;
var now;
var fromDate;
var toDate;
var events;

// Инициализация
(function() {
    contactsCal = CalendarApp.getCalendarById('addressbook#contacts@group.v.calendar.google.com');
    defaultCal = CalendarApp.getDefaultCalendar(); // создаем события в календаре по умолчанию
    // var defaultCal = CalendarApp.getCalendarById('regrncqXXXXXXp07eihepag74@group.calendar.google.com'); //или другой календарь

    now = new Date();
    fromDate = new Date(now.getTime());
    toDate = new Date(now.getTime() + 31 * (1000 * 60 * 60 * 24)); // + 31 дней от текущей даты
    Logger.log('С даты: ' + Utilities.formatDate(fromDate, 'Asia/Yekaterinburg', 'MMMM dd, yyyy HH:mm:ss Z'));
    Logger.log('По дату: ' + Utilities.formatDate(toDate, 'Asia/Yekaterinburg', 'MMMM dd, yyyy HH:mm:ss Z'));
    events = contactsCal.getEvents(fromDate, toDate);
    Logger.log('Найдено событий: ' + events.length);
})();

function birthdayAgeToCalendar() { //дни рождения
    for (var i in events) {
        Logger.log('birthdayAgeToCalendar. дни рождения. Найдено: ' + events[i].getTitle());
        var name = events[i].getTitle().split(" – день рождения")[0];
        var contacts = ContactsApp.getContactsByName(name);
        Logger.log('birthdayAgeToCalendar. дни рождения. Name: ' + name);

        for (var c in contacts) {
            var bday = contacts[c].getDates(ContactsApp.Field.BIRTHDAY);
            var bdayMonthName, bdayYear, bdayDate;
            try {
                bdayMonthName = bday[0].getMonth();
                bdayYear = bday[0].getYear();
                bdayDate = new Date(bdayMonthName + ' ' + bday[0].getDay() + ', ' + bdayYear);
                Logger.log('birthdayAgeToCalendar. bdayDate: ' + bdayDate);
            } catch (error) {}

            var years = parseInt(new Date().getFullYear()) - bdayYear;
            try {
                defaultCal.createAllDayEvent(name + " – день рождения, " + years + " лет (года)",
                    new Date(bdayMonthName + ' ' + bday[0].getDay() + ', ' + new Date().getFullYear()));
                Logger.log("Создано: " + name + " – день рождения, " + years + " лет (года)");
            } catch (error) {}
        }
    }
}

function anniversaryAgeToCalendar() { //юбилеи
    for (var i in events) {
        Logger.log('anniversaryAgeToCalendar. Юбилеи. Найдено: ' + events[i].getTitle());
        var name = events[i].getTitle().split("Юбилей у пользователя ")[1];
        var contacts = ContactsApp.getContactsByName(name);
        Logger.log('anniversaryAgeToCalendar. юбилеи. Name: ' + name);

        for (var c in contacts) {
            var bday = contacts[c].getDates(ContactsApp.Field.ANNIVERSARY); //существующие типы данных https://developers.google.com/apps-script/reference/contacts/field
            var bdayMonthName, bdayYear, bdayDate;
            try {
                bdayMonthName = bday[0].getMonth();
                bdayYear = bday[0].getYear();
                bdayDate = new Date(bdayMonthName + ' ' + bday[0].getDay() + ', ' + bdayYear);
                Logger.log('anniversaryAgeToCalendar. bdayDate: ' + bdayDate);
            } catch (error) {}

            var years = parseInt(new Date().getFullYear()) - bdayYear;
            try {
                defaultCal.createAllDayEvent("Юбилей у пользователя " + name + ", " + years + " лет (года)",
                    new Date(bdayMonthName + ' ' + bday[0].getDay() + ', ' + new Date().getFullYear()));
                Logger.log("Создано: " + "Юбилей у пользователя " + name + ", " + years + " лет (года)");
            } catch (error) {}
        }
    }
}

function TriggersCreateTimeDriven() { //автоматически создаем новые триггеры для запуска
    // Deletes all triggers in the current project.
    var triggers = ScriptApp.getProjectTriggers();
    for (var i = 0; i < triggers.length; i++) {
        ScriptApp.deleteTrigger(triggers[i]);
    }
    // а теперь создаем
    ScriptApp.newTrigger("birthdayAgeToCalendar") //дни рождения
        .timeBased()
        .onMonthDay(1) //день месяца
        .atHour(1)
        .create();
    ScriptApp.newTrigger("anniversaryAgeToCalendar") //юбилеи
        .timeBased()
        .onMonthDay(1)
        .atHour(2)
        .create();
}

Как пользоваться?


1.Создайте новый Google Apps Script на гугл диске:



2.Скопируйте код скрипта.


3.Тестово запустите функцию “birthdayAgeToCalendar” — скрипт создаст события в календаре по умолчанию с указанием возраста для людей, у которых в течении 31 дня (но в текущем году) будет дни рождения:



4.Посмотрите Вид/Журналы:



5.Проверьте календарь:



6.Если всё в порядке запустите функцию “TriggersCreateTimeDriven” — она создаст автозапуск функций “birthdayAgeToCalendar” и “anniversaryAgeToCalendar” на каждое первое число на месяц вперед.


Итог


Считаю, что проблема отображения возраста в Гугл календаре при наступлении значимых событий решена. Также я хочу поблагодарить Евгения Намоконова (телеграм канал “Google Таблицы”) и Александра Иванова вместе с его телеграм каналом за помощь в напутствии и редактировании написанного кода.


Дополнительные подробности можно найти на GitHub.


Автор: Михаил Шардин,
25 декабря 2019 г.

Комментарии (18)


  1. DimNS
    25.12.2019 12:05

    Для тех у кого нет в меню такого пункта «Google Apps Script» там же надо нажать «Подключить другие приложения» и в поиске найти «Google Apps Script» и подключить, тогда пункт в меню появится


  1. webviktor
    25.12.2019 12:20

    Потому, что никто после 25 не хочет знать свой возраст.


    1. empenoso Автор
      25.12.2019 14:26

      Или не помнит


  1. EvilsInterrupt
    25.12.2019 13:14

    То что не указывается возраст это фича, а не бага!


  1. Digger44
    25.12.2019 14:18

    Интересный скрипт. Спасибо! Скажите, а как можно поменять время оповещение в календаре? И оповещение по электронной почте у меня не появилось. Это отдельно настраивается?


    1. empenoso Автор
      25.12.2019 14:25

      Напоминания скриптом отдельно задавать надо:


      event.addPopupReminder(12 * 60 + 5 * 24 * 60); //за 5 дней


  1. Budilnik1
    25.12.2019 14:18

    Что-то у меня ничего не находит «Найдено событий: 0». Поля «День рождения» в контактах заполнены правильно. На ближайший месяц таких контактов несколько.


    1. empenoso Автор
      25.12.2019 14:19

      А в стандартном календаре Контакты — эти дни рождения есть?


      https://calendar.google.com/calendar/htmlembed?src=addressbook%23contacts%40group.v.calendar.google.com


      1. Budilnik1
        25.12.2019 14:53

        Нет. Дни рождения есть только в Гугл.Контактах. Я понял из статьи, что данные извлекаются именно из Гугл.Контактов и создаются напоминания в стандартном Гугл.Календаре. Это не так?


        1. empenoso Автор
          25.12.2019 15:00

          Если в этом календаре нет, то и после работы скрипта они не появятся. Скрипт сканирует этот стандартный календарь, затем ищет данные на контакт в Гугл.Контактах и затем создает в календаре по умолчанию событие с возрастом.


          Возможно формат даты неправильно указан?


          1. Budilnik1
            25.12.2019 15:07

            Может, если вас не затруднит, подскажете, как данные из поля «День рождения» в Гугл.Контатах попадают в Календарь.Contacts? Не понимаю почему в Гугл.контактах дни рождения заполнены, а в Календарь.Contacts — пусто…


            1. empenoso Автор
              25.12.2019 15:20

              Формат даты не тот указан наверное. Попробуйте в разных форматах записать.
              И они не в туже секунду появляются в Календаре Contacts — счет на минуты.


  1. LDZ
    25.12.2019 22:35

    Корректно работает с ДР 29 февраля?

    Странно, что решили запускать только 1 числа и только на 1 месяц вперед
    Потому что еси у человека ДР 1-го числа, то я узнаю об этом только 1-го числа, а не заранее.

    А сама идея хороша!


    1. empenoso Автор
      26.12.2019 08:51

      С 1 февраля на 31 день вперед покрывает и 29 февраля :)
      1 числа и только на 1 месяц вперед — чтобы не было дублей — ведь они не отслеживаются, а если какого-то нового человека добавите — за этот месяц и если больший срок, то есть шанс что у него не будет создано мероприятие — он просто не успеет попасть под запуск скрипта.


      1. LDZ
        26.12.2019 10:39

        по поводу 29 февраля — если год невисокосный, а у человека ДР 29 февраля, то соответственно, напоминание не появится вообще? Ни на 1 марта, ни на 28 февраля?


        1. empenoso Автор
          26.12.2019 12:13

          Я не проводил отдельных тестов, но на мой взгляд, логика работы скрипта не нарушается и если ДР 29 февраля — все должно работать, не вижу проблемы.


          1. LDZ
            26.12.2019 12:17

            А на какое число он добавит напоминание, если в текущем году нет 29 февраля?


            1. empenoso Автор
              26.12.2019 16:43

              Это хороший вопрос и я не знаю ответ.