├── Automation in waybills through Google spreadsheets and scripts in 2023.gs ├── Autoresponder for file access requests in Google mail.gs ├── Google Calendar_A child’s age_v1.gs ├── Google Calendar_A child’s age_v1.png ├── Google Calendar_A child’s age_v2.gs ├── Google Calendar_A child’s age_v2.png ├── Google Calendar_A child’s age_v3.gs ├── Google Calendar_A child’s age_v3.png ├── Google Calendar_Birthdays.gs ├── Google Calendar_Birthdays.png ├── Google Calendar_Birthdays_v2.gs ├── Google Calendar_Birthdays_v2.png ├── How to create multiple documents based on a single template using a script inside Google Sheets.gs ├── LICENSE ├── README.md └── README.ru.md /Automation in waybills through Google spreadsheets and scripts in 2023.gs: -------------------------------------------------------------------------------- 1 | // Путевой лист — это такой документ, который является основанием для списания горючего в состав расходов в бухгалтерском и налоговом учёте. А ещё путевые листы нужны, чтобы обосновать необходимость аренды или лизинга автотранспорта. 2 | 3 | // Однако путевой лист достаточно запутанный первичный документ и на его заполнение можно потратить много времени. И это время нужно тратить регулярно. Эта статья - моя попытка сделать универсальный шаблон в гугл таблицах с возможностью полного автоматического заполнения буквально в два клика. 4 | 5 | // Мой шаблон не претендует на соответствие всем действующим нормам, а в первую очередь нацелен на кардинальное уменьшение времени, которое тратится на заполнение путевого листа. 6 | 7 | // При этом заполнение происходит рандомно сгенерированными данными на основании всего нескольких достоверных начальных параметров: начального и конечного показания одометра автомобиля и задания точного района, где эксплуатируется этот автомобиль. 8 | 9 | // https://habr.com/ru/articles/710584/ -------------------------------------------------------------------------------- /Autoresponder for file access requests in Google mail.gs: -------------------------------------------------------------------------------- 1 | // Подробное описание в статье https://habr.com/ru/articles/739168/ 2 | 3 | function autoReply() { 4 | for (const filename of [ 5 | `Имя файла 1`, 6 | `Имя файла 2`, 7 | `Имя файла 3` 8 | ]) { 9 | var threads = GmailApp.search(`is:inbox is:unread Запрос доступа к файлу "${filename}"`); 10 | for (var i = 0; i < threads.length; i++) { 11 | var thread = threads[i]; 12 | console.log(`Результат поиска: "${filename}": ${i} из ${threads.length}:\n---- ${thread.getMessages()[thread.getMessageCount() - 1].getReplyTo()};`) 13 | from = thread 14 | .getMessages()[thread.getMessageCount() - 1].getFrom() 15 | .split(' (через')[0] 16 | .replace(/\"/g, '') 17 | thread.reply(`Привет, ${from}!\nБлагодарю Вас за интерес к моему файлу "${filename}". Бла бла бла \n\nС уважением, Михаил Шардин.`); 18 | GmailApp.moveThreadsToTrash(threads.slice(i, i + 1)); 19 | 20 | console.log(`Был обработан и удалён запрос от ${thread.getMessages()[thread.getMessageCount() - 1].getReplyTo()} к ${filename}`) 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /Google Calendar_A child’s age_v1.gs: -------------------------------------------------------------------------------- 1 | /* 2 | * Для всех молодых отцов - сколько месяцев и годов ребенку отроду, ежемесячная напоминалка. 3 | * A child’s age in months and years, with a monthly reminder 4 | * (c) 2019.10 Mikhail Shardin https://shardin.name/ 5 | * 6 | * Написал код, который облегчает жизнь молодым отцам. 7 | * Ведь в то время как все бабушки отлично помнят день 8 | * рождения своего внука/внучки и поздравляют с этим 9 | * событием ежемесячно - мне никак не удавалось удержать 10 | * это в памяти. Решил слегка автоматизировать процесс и 11 | * заодно разобраться как работать с датами в Google Apps Script. 12 | * И конечно же сделать, чтобы эта напоминалка появлялась 13 | * заблаговременно, а не в день рождения малыша! 14 | 15 | * Для начала работы Файл/Создать копию и задать 16 | * начальное значение offset из того расчета, что триггер на 17 | * автоматический запуск скрипта 1 числа каждого месяца, 18 | * но сам день рождения например 8 числа, то есть offset 19 | * должен быть равен 7. 20 | 21 | * Функция TriggersCreateTimeDriven создаст 22 | * автозапуск расчетов каждого 1го числа месяца. 23 | * 24 | * Дополнительные инструкции: https://github.com/empenoso/Google-Apps-Script/ 25 | * https://script.google.com/d/1JxcGYj9q5XldP5RaTzsiRgshGmR8_ElcjmcmKxmu4tRKPO9lwFMjK832/edit?usp=drive_web 26 | * 27 | * На основе кода Eric Koleda 28 | * https://stackoverflow.com/questions/16149760/calculating-year-month-days-between-dates-in-google-apps-script/16928369 29 | */ 30 | 31 | function AddCalendarCurrentAge() { //вычисляем возраст всех участников и добавляем в выбраный календарь 32 | eval(UrlFetchApp.fetch('https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment-with-locales.min.js').getContentText()); 33 | moment.locale('ru'); 34 | var offset = 7; 35 | var now = new Date(new Date().setDate(new Date().getDate() + offset)); // триггер из TriggersCreateTimeDriven работает в 1й день месяца, но само день рождение ведь в другой день, поэтому + n дней 36 | 37 | var child = new Date('April 17, 2017'); //https://translate.google.com/#view=home&op=translate&sl=ru&tl=en&text=17%20%D0%B0%D0%BF%D1%80%D0%B5%D0%BB%D1%8F%202017%20%D0%B3%D0%BE%D0%B4%D0%B0 38 | var childAge = getDuration(child, now); 39 | childAge = childAge.replace(/years/g, "года"); 40 | childAge = childAge.replace(/months/g, "месяцев"); 41 | childAge = childAge.replace(/days/g, "дней"); 42 | Logger.log("child age = %s", childAge); 43 | 44 | var relations = new Date('June 11, 2014 15:00:00 +0500'); 45 | var relationsAge = getDuration(relations, now); 46 | relationsAge = relationsAge.replace(/years/g, "лет"); 47 | relationsAge = relationsAge.replace(/months/g, "месяцев"); 48 | relationsAge = relationsAge.replace(/days/g, "дней"); 49 | Logger.log("relationship age = %s", relationsAge); 50 | 51 | var fathersAge = moment("19880515", "YYYYMMDD").fromNow(); 52 | Logger.log("father's age = %s", fathersAge); 53 | 54 | var motherAge = moment("19900418", "YYYYMMDD").fromNow(); 55 | Logger.log("mother age = %s", motherAge); 56 | 57 | // добавляем в календарь 58 | var defaultCal = CalendarApp.getDefaultCalendar(); // создаем события в календаре по умолчанию 59 | //var defaultCal = CalendarApp.getCalendarById('XXXXXXX@group.calendar.google.com'); //или другом календаре. узнать идентификатор через функцию get_calendars ниже 60 | var title = "XXXXXXX сегодня " + childAge; 61 | var event = defaultCal.createAllDayEvent(title, 62 | now, { 63 | location: "XXXXXXX", 64 | description: 'Мама родилась ' + motherAge + ', папа ' + fathersAge + '.\n' + 'Первая встреча мамы и папы ' + relationsAge + ' назад.' 65 | }); 66 | event.setColor(CalendarApp.EventColor.RED); 67 | event.addPopupReminder(12 * 60 + 5 * 24 * 60); //за 5 дней 68 | } 69 | 70 | function TriggersCreateTimeDriven() { //автоматически создаем новые триггеры для запуска 71 | // Deletes all triggers in the current project. 72 | var triggers = ScriptApp.getProjectTriggers(); 73 | for (var i = 0; i < triggers.length; i++) { 74 | ScriptApp.deleteTrigger(triggers[i]); 75 | } 76 | // а теперь создаем 77 | ScriptApp.newTrigger("AddCalendarCurrentAge") 78 | .timeBased() 79 | .onMonthDay(1) //триггер на 1й день месяца 80 | .atHour(2) 81 | .create(); 82 | } 83 | 84 | function getDuration(startDate, endDate) { // функция вычисляющая возраст в днях 85 | var start = moment(startDate); 86 | var end = moment(endDate); 87 | var units = ['years', 'months', 'days']; 88 | var parts = []; 89 | units.forEach(function(unit, i) { 90 | var diff = Math.floor(end.diff(start, unit, true)); 91 | if (diff > 0 || i == units.length - 1) { 92 | end.subtract(unit, diff); 93 | parts.push(diff + ' ' + unit); 94 | } 95 | }) 96 | return parts.join(', '); 97 | } 98 | 99 | //================================================================================================= 100 | 101 | function get_calendars() { //получить список всех доступных календарей 102 | var calendars = CalendarApp.getAllCalendars(); 103 | Logger.log('This user owns or is subscribed to %s calendars.', calendars.length); 104 | for (var i = 0; i < calendars.length; i++) { 105 | var calendar = calendars[i]; 106 | Logger.log((i + 1) + 'й календарь: "' + calendar.getName() + '",\n ID: "' + calendar.getId() + '"\n'); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Google Calendar_A child’s age_v1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/empenoso/Google-Apps-Script/df76d22855e6f500dad3a062c1139efe67e7e6dd/Google Calendar_A child’s age_v1.png -------------------------------------------------------------------------------- /Google Calendar_A child’s age_v2.gs: -------------------------------------------------------------------------------- 1 | /* 2 | * Скрипт, который ежемесячно создаёт событие в гугл календаре, в котором точно указан возраст ребенка, а также значимые события из жизни родителей 3 | * (c) 2022.01. Mikhail Shardin https://shardin.name/ 4 | * 5 | * Дополнительные инструкции: https://habr.com/ru/post/645935/ 6 | * Исходное размещение: https://github.com/empenoso/Google-Apps-Script/ 7 | */ 8 | 9 | function AddCalendarCurrentAge() { //вычисляем значимые даты и добавляем всё это в выбраный календарь 10 | eval(UrlFetchApp.fetch('https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment-with-locales.min.js').getContentText()); 11 | moment.locale('ru'); 12 | 13 | const offset = 9; 14 | var now = moment().add(offset, 'days'); // триггер из TriggersCreateTimeDriven работает в 1й день месяца, но сам день рождения ведь в другой день, то есть если день рождения ребёнка 9 числа, то offset = 9 15 | 16 | const childBirthday = '2017-03-07' 17 | var childFullYears = ~~(moment(now).diff(childBirthday, 'months', false) / 12) 18 | childText = `Ребенок родился ${childFullYears} года и ${moment().diff(childBirthday, 'months', false)-childFullYears*12} месяцев назад.` 19 | 20 | const fatherBirthday = '1991-06-15' 21 | var fatherFullYears = ~~(moment(now).diff(fatherBirthday, 'months', false) / 12) 22 | fatherText = `Папа родился ${fatherFullYears} лет и ${moment().diff(fatherBirthday, 'months', false)-fatherFullYears*12} месяцев назад.` 23 | 24 | const motherBirthday = '1995-07-18' 25 | var motherFullYears = ~~(moment(now).diff(motherBirthday, 'months', false) / 12) 26 | motherText = `Мама родилась ${motherFullYears} лет и ${moment().diff(motherBirthday, 'months', false)-motherFullYears*12} месяцев назад.` 27 | 28 | const relationshipStart = '2015-06-16' 29 | const relationshipEnd = moment().format('YYYY-MM-DD') // или поставьте дату :( 30 | var relationshipFullYears = ~~(moment(relationshipEnd).diff(relationshipStart, 'months', false) / 12) 31 | relationshipText = `Отношениям ${relationshipFullYears} лет и ${moment(relationshipEnd).diff(relationshipStart, 'months', false)-relationshipFullYears*12} месяцев (с ${relationshipStart} по ${relationshipEnd}).` 32 | Logger.log(childText + '\n' + fatherText + '\n' + motherText + '\n' + relationshipText); 33 | 34 | // добавляем в календарь 35 | var defaultCal = CalendarApp.getDefaultCalendar(); // создаем события в календаре по умолчанию 36 | // var defaultCal = CalendarApp.getCalendarById('54r4muXXXXXXXXXvgh4vr2h8@group.calendar.google.com'); //или другом календаре. узнать идентификатор через функцию get_calendars ниже 37 | 38 | var title = `Ребенку сегодня исполняется ${childFullYears} года и ${moment().diff(childBirthday, 'months', false)-childFullYears*12} месяцев`; 39 | var event = defaultCal.createAllDayEvent(title, 40 | new Date(now), { 41 | location: "58.0100442,56.2275679", 42 | description: motherText + '\n' + fatherText + '\n\n' + relationshipText 43 | }); 44 | event.setColor(CalendarApp.EventColor.RED); 45 | event.addPopupReminder(12 * 60 + 5 * 24 * 60); //за 5 дней 46 | } 47 | 48 | function TriggersCreateTimeDriven() { //автоматически создаем новые триггеры для запуска 49 | // Deletes all triggers in the current project. 50 | var triggers = ScriptApp.getProjectTriggers(); 51 | for (var i = 0; i < triggers.length; i++) { 52 | ScriptApp.deleteTrigger(triggers[i]); 53 | } 54 | // а теперь создаем 55 | ScriptApp.newTrigger("AddCalendarCurrentAge") 56 | .timeBased() 57 | .onMonthDay(1) //триггер на 1й день месяца 58 | .atHour(2) 59 | .create(); 60 | } 61 | 62 | //================================================================================================= 63 | 64 | function getCalendars() { //получить список идентификаторов всех доступных календарей 65 | var calendars = CalendarApp.getAllCalendars(); 66 | Logger.log('Этот пользователь подписан на %s календарей:', calendars.length); 67 | for (var i = 0; i < calendars.length; i++) { 68 | var calendar = calendars[i]; 69 | Logger.log((i + 1) + 'й календарь: "' + calendar.getName() + '",\n ID: "' + calendar.getId() + '"\n'); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Google Calendar_A child’s age_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/empenoso/Google-Apps-Script/df76d22855e6f500dad3a062c1139efe67e7e6dd/Google Calendar_A child’s age_v2.png -------------------------------------------------------------------------------- /Google Calendar_A child’s age_v3.gs: -------------------------------------------------------------------------------- 1 | /* 2 | * Для всех молодых отцов - сколько месяцев и годов ребенку отроду, ежемесячная напоминалка в Гугл календаре 3 | * A child’s age in months and years, with a monthly reminder 4 | * 5 | * (c) 2022.08 Mikhail Shardin https://shardin.name/ 6 | * 7 | * Инструкции как пользоваться: https://habr.com/ru/post/683188/ 8 | * Актуальная версия: https://github.com/empenoso/Google-Apps-Script/ 9 | * 10 | * Этот скрипт модификация моей версии января 2022 года: https://habr.com/ru/post/645935/ 11 | * 12 | * Спасибо @Sergey_050krd (это ссылка на телеграм) за склонение год, лет, года и создание комментариев. 13 | * 14 | */ 15 | 16 | // Вычисляем значимые даты и добавляем всё это в выбраный календарь 17 | function AddCalendarCurrentAge() { 18 | eval(UrlFetchApp.fetch('https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment-with-locales.min.js').getContentText()); 19 | moment.locale('ru'); 20 | 21 | // Триггер из TriggersCreateTimeDriven работает в 1-й день месяца, но сам день рождения ведь в другой день, 22 | // то есть если день рождения ребёнка 9 числа, то offset = 8 23 | const offset = 6; 24 | var now = moment().add(offset, 'days'); 25 | 26 | // Данные о рождении папы. Вычисляем возраст папы: полных лет, месяцев 27 | const fatherBirthday = '1994-05-15' 28 | var fatherFullYears = ~~(moment(now).diff(fatherBirthday, 'months', false) / 12); 29 | var fathermonth = (moment().diff(fatherBirthday, 'months', false) - fatherFullYears * 12); 30 | fatherText = "Папа родился " + fatherFullYears + ' ' + textYear(fatherFullYears) + ' ' + "и " + fathermonth + ' ' + textMonth(fathermonth) + ' ' + "назад. "; 31 | 32 | // Данные о рождении мамы. Вычисляем возраст мамы: полных лет, месяцев 33 | const motherBirthday = '1996-04-18' 34 | var motherFullYears = ~~(moment(now).diff(motherBirthday, 'months', false) / 12); 35 | var mothermonth = (moment().diff(motherBirthday, 'months', false) - motherFullYears * 12); 36 | motherText = "Мама родилась " + motherFullYears + ' ' + textYear(motherFullYears) + ' ' + "и " + mothermonth + ' ' + textMonth(mothermonth) + ' ' + "назад. "; 37 | 38 | // Данные о рождении ребёнка. Вычисляем возраст ребёнка: полных лет, месяцев 39 | const childBirthday = '2020-04-07' 40 | var childFullYears = ~~(moment(now).diff(childBirthday, 'months', false) / 12); 41 | var childmonth = (moment().diff(childBirthday, 'months', false) - childFullYears * 12); 42 | childText = "Ребёнок родился " + childFullYears + ' ' + textYear(childFullYears) + ' ' + "и " + childmonth + ' ' + textMonth(childmonth) + ' ' + "назад. "; 43 | 44 | // Данные об отношених. Вычисляем: полных лет, месяцев 45 | const relationshipStart = '2017-06-16' 46 | const relationshipEnd = moment().format('YYYY-MM-DD'); // или поставьте дату :( 47 | var relationshipFullYears = ~~(moment(relationshipEnd).diff(relationshipStart, 'months', false) / 12); 48 | var relationshipmonth = ~~(moment(relationshipEnd).diff(relationshipStart, 'months', false) - relationshipFullYears * 12); 49 | var freeFullYears = ~~(moment().diff(relationshipEnd, 'months', false) / 12) 50 | relationshipText = "Отношениям папы и мамы " + relationshipFullYears + ' ' + textYear(relationshipFullYears) + ' ' + "и " + relationshipmonth + ' ' + textMonth(relationshipmonth) + ` (с ${relationshipStart} по ${relationshipEnd}).` 51 | // + `\n\nУже ${freeFullYears} лет ${moment().diff(relationshipEnd, 'months', false)-freeFullYears*12} месяцев родители живут порознь.` 52 | 53 | Logger.log(childText + '\n' + fatherText + '\n' + motherText + '\n' + relationshipText); 54 | 55 | // Создаем события в календаре по умолчанию 56 | var defaultCal = CalendarApp.getDefaultCalendar(); 57 | 58 | // Или создаем события в другом календаре. Узнать идентификатор календаря через функцию get_calendars ниже 59 | // var defaultCal = CalendarApp.getCalendarById('54r4muXXXXXXXXXvgh4vr2h8@group.calendar.google.com'); 60 | 61 | var title = `Сегодня ребёнку исполняется ${childFullYears} ${textYear(childFullYears)} и ${moment().diff(childBirthday, 'months', false)-childFullYears*12} ${textMonth(childmonth)}`; 62 | var event = defaultCal.createAllDayEvent(title, 63 | new Date(now), { 64 | // location: "Пермь", 65 | description: fatherText + '\n' + motherText + '\n\n' + relationshipText 66 | }); 67 | event.setColor(CalendarApp.EventColor.RED); 68 | // event.addPopupReminder(24 * 60 * 2 - 9 * 60); // за 2 дня в 09:00 69 | // event.addPopupReminder(24 * 60 * 1 - 9 * 60); // за 1 день в 09:00 70 | event.addPopupReminder(4 * 60); // за 1 день в 20:00 71 | // event.addPopupReminder(0); // в тот же день в 00:00 72 | 73 | logToDrive(); //создаем файл лога на Гугл диске 74 | } 75 | 76 | // Получаем список идентификаторов всех доступных календарей 77 | function getCalendars() { 78 | var calendars = CalendarApp.getAllCalendars(); 79 | Logger.log('Этот пользователь подписан на %s календарей:', calendars.length); 80 | for (var i = 0; i < calendars.length; i++) { 81 | var calendar = calendars[i]; 82 | Logger.log((i + 1) + 'й календарь: "' + calendar.getName() + '",\n ID: "' + calendar.getId() + '"\n'); 83 | } 84 | } 85 | 86 | // Склоняем возраст в годах 87 | function textYear(age) { 88 | var years; 89 | count = age % 100; 90 | if (count >= 5 && count <= 20) { 91 | years = 'лет'; 92 | } else { 93 | count = count % 10; 94 | if (count == 1) { 95 | years = 'год'; 96 | } else if (count >= 2 && count <= 4) { 97 | years = 'года'; 98 | } else { 99 | years = 'лет'; 100 | } 101 | } 102 | return years; 103 | } 104 | 105 | // Склоняем возраст в месяцах 106 | function textMonth(month) { 107 | var month; 108 | count = month % 100; 109 | if (count >= 5 && count <= 20) { 110 | month = 'месяцев'; 111 | } else { 112 | count = count % 10; 113 | if (count == 1) { 114 | month = 'месяц'; 115 | } else if (count >= 2 && count <= 4) { 116 | month = 'месяца'; 117 | } else { 118 | month = 'месяцев'; 119 | } 120 | } 121 | return month; 122 | } 123 | 124 | // Автоматически создаем новые триггеры для запуска 125 | function TriggersCreateTimeDriven() { 126 | // Deletes all triggers in the current project. 127 | var triggers = ScriptApp.getProjectTriggers(); 128 | for (var i = 0; i < triggers.length; i++) { 129 | ScriptApp.deleteTrigger(triggers[i]); 130 | } 131 | // а теперь создаем 132 | ScriptApp.newTrigger("AddCalendarCurrentAge") 133 | .timeBased() 134 | .onMonthDay(1) //триггер на 1й день месяца 135 | .atHour(2) 136 | .create(); 137 | } 138 | 139 | function logToDrive() { //создаем файл лога на диске 140 | var id = ScriptApp.getScriptId(); 141 | var name = DriveApp.getFileById(id).getName(); 142 | // определяем имя папки - начало 143 | var file = DriveApp.getFileById(id); 144 | var folders = file.getParents(); 145 | while (folders.hasNext()) { 146 | var folder_name = folders.next().getName(); 147 | Logger.log("logToDrive. Имя папки: " + folder_name) 148 | } 149 | // определяем имя папки - конец 150 | var fileName = name + "_GoogleAppsLog.txt"; 151 | try { 152 | var dir = DriveApp.getFoldersByName(folder_name).next(); //если в какой-то папке 153 | } catch (error) { 154 | var dir = DriveApp.getRootFolder(); //если корень диска 155 | } 156 | 157 | var files = dir.getFiles(); 158 | while (files.hasNext()) { 159 | var file = files.next(); 160 | Logger.log("logToDrive. Файлы в папке: " + file.getName()) 161 | if (file.getName() === fileName) { 162 | file.setTrashed(true); //удаляем предыдущий лог файл 163 | break; 164 | } 165 | } 166 | var file = dir.createFile(fileName, Logger.getLog()); //создаем лог файл 167 | } 168 | -------------------------------------------------------------------------------- /Google Calendar_A child’s age_v3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/empenoso/Google-Apps-Script/df76d22855e6f500dad3a062c1139efe67e7e6dd/Google Calendar_A child’s age_v3.png -------------------------------------------------------------------------------- /Google Calendar_Birthdays.gs: -------------------------------------------------------------------------------- 1 | /* 2 | * Создает события (дни рождения и юбилеи) с указанием прошедших лет в календаре 3 | * Birthdays and anniversaries with dates for your Google Calendar 4 | * (c) 2019.03 Mikhail Shardin https://shardin.name/ 5 | * 6 | * Меня, как пользователя телефона с системой Android, всегда не очень устраивал тот факт, 7 | * что в моём календаре были обозначены дни рождения контактов, но без указания возраста человека. 8 | * Также и с юбилеями контактов - вроде бы юбилей есть, а сколько времени прошло с этого события непонятно. 9 | * Переходить в сам контакт и смотреть год рождения или дату юбилея, а потом что-то рассчитывать - на это времени никогда не было. 10 | * Решил сам себе упростить жизнь и написал Google Apps Script, который сначала ищет эти события в специальном календаре, 11 | * который по умолчанию выводит эти события. А зачем на втором шаге рассчитывает возраст для конкретных контактов и уже создает события в основном календаре. 12 | * 13 | * Дополнительные инструкции: https://habr.com/ru/post/481858/ 14 | * https://script.google.com/d/1oDswSXp_UleDXiTFushWnqziHi1Dlkb6x_neteWWKfEnjXttUUIPyRTd/edit?usp=sharing 15 | * UPD 04.2019: теперь с правками кода от Alexander Ivanov - https://github.com/contributorpw/ 16 | * 17 | * Для начала работы Файл/Создать копию и выполнить TriggersCreateTimeDriven - создаст автозапуск каждого 1го числа месяца и делает расчет на 31 день вперед 18 | * 19 | * На основе кодов Bryan Patterson - scripts@bryanp.com 20 | * https://productforums.google.com/forum/#!topic/calendar/B-i5hoBhTiw 21 | */ 22 | 23 | /* exported birthdayAgeToCalendar, anniversaryAgeToCalendar, TriggersCreateTimeDriven */ 24 | 25 | // Глобальные переменные 26 | var contactsCal; 27 | var defaultCal; 28 | var now; 29 | var fromDate; 30 | var toDate; 31 | var events; 32 | 33 | // Инициализация 34 | (function() { 35 | contactsCal = CalendarApp.getCalendarById('addressbook#contacts@group.v.calendar.google.com'); 36 | defaultCal = CalendarApp.getDefaultCalendar(); // создаем события в календаре по умолчанию 37 | // var defaultCal = CalendarApp.getCalendarById('regrncqXXXXXXp07eihepag74@group.calendar.google.com'); //или другой календарь 38 | 39 | now = new Date(); 40 | fromDate = new Date(now.getTime()); 41 | toDate = new Date(now.getTime() + 31 * (1000 * 60 * 60 * 24)); // + 31 дней от текущей даты 42 | Logger.log('С даты: ' + Utilities.formatDate(fromDate, 'Asia/Yekaterinburg', 'MMMM dd, yyyy HH:mm:ss Z')); 43 | Logger.log('По дату: ' + Utilities.formatDate(toDate, 'Asia/Yekaterinburg', 'MMMM dd, yyyy HH:mm:ss Z')); 44 | events = contactsCal.getEvents(fromDate, toDate); 45 | Logger.log('Найдено событий: ' + events.length); 46 | })(); 47 | 48 | function birthdayAgeToCalendar() { //дни рождения 49 | for (var i in events) { 50 | Logger.log('birthdayAgeToCalendar. дни рождения. Найдено: ' + events[i].getTitle()); 51 | var name = events[i].getTitle().split(" – день рождения")[0]; 52 | var contacts = ContactsApp.getContactsByName(name); 53 | Logger.log('birthdayAgeToCalendar. дни рождения. Name: ' + name); 54 | 55 | for (var c in contacts) { 56 | var bday = contacts[c].getDates(ContactsApp.Field.BIRTHDAY); 57 | var bdayMonthName, bdayYear, bdayDate; 58 | try { 59 | bdayMonthName = bday[0].getMonth(); 60 | bdayYear = bday[0].getYear(); 61 | bdayDate = new Date(bdayMonthName + ' ' + bday[0].getDay() + ', ' + bdayYear); 62 | Logger.log('birthdayAgeToCalendar. bdayDate: ' + bdayDate); 63 | } catch (error) {} 64 | 65 | var years = parseInt(new Date().getFullYear()) - bdayYear; 66 | try { 67 | defaultCal.createAllDayEvent(name + " – день рождения, " + years + " лет (года)", 68 | new Date(bdayMonthName + ' ' + bday[0].getDay() + ', ' + new Date().getFullYear())); 69 | Logger.log("Создано: " + name + " – день рождения, " + years + " лет (года)"); 70 | } catch (error) {} 71 | } 72 | } 73 | } 74 | 75 | function anniversaryAgeToCalendar() { //юбилеи 76 | for (var i in events) { 77 | Logger.log('anniversaryAgeToCalendar. Юбилеи. Найдено: ' + events[i].getTitle()); 78 | var name = events[i].getTitle().split("Юбилей у пользователя ")[1]; 79 | var contacts = ContactsApp.getContactsByName(name); 80 | Logger.log('anniversaryAgeToCalendar. юбилеи. Name: ' + name); 81 | 82 | for (var c in contacts) { 83 | var bday = contacts[c].getDates(ContactsApp.Field.ANNIVERSARY); //существующие типы данных https://developers.google.com/apps-script/reference/contacts/field 84 | var bdayMonthName, bdayYear, bdayDate; 85 | try { 86 | bdayMonthName = bday[0].getMonth(); 87 | bdayYear = bday[0].getYear(); 88 | bdayDate = new Date(bdayMonthName + ' ' + bday[0].getDay() + ', ' + bdayYear); 89 | Logger.log('anniversaryAgeToCalendar. bdayDate: ' + bdayDate); 90 | } catch (error) {} 91 | 92 | var years = parseInt(new Date().getFullYear()) - bdayYear; 93 | try { 94 | defaultCal.createAllDayEvent("Юбилей у пользователя " + name + ", " + years + " лет (года)", 95 | new Date(bdayMonthName + ' ' + bday[0].getDay() + ', ' + new Date().getFullYear())); 96 | Logger.log("Создано: " + "Юбилей у пользователя " + name + ", " + years + " лет (года)"); 97 | } catch (error) {} 98 | } 99 | } 100 | } 101 | 102 | function TriggersCreateTimeDriven() { //автоматически создаем новые триггеры для запуска 103 | // Deletes all triggers in the current project. 104 | var triggers = ScriptApp.getProjectTriggers(); 105 | for (var i = 0; i < triggers.length; i++) { 106 | ScriptApp.deleteTrigger(triggers[i]); 107 | } 108 | // а теперь создаем 109 | ScriptApp.newTrigger("birthdayAgeToCalendar") //дни рождения 110 | .timeBased() 111 | .onMonthDay(1) //день месяца 112 | .atHour(1) 113 | .create(); 114 | ScriptApp.newTrigger("anniversaryAgeToCalendar") //юбилеи 115 | .timeBased() 116 | .onMonthDay(1) 117 | .atHour(2) 118 | .create(); 119 | } 120 | -------------------------------------------------------------------------------- /Google Calendar_Birthdays.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/empenoso/Google-Apps-Script/df76d22855e6f500dad3a062c1139efe67e7e6dd/Google Calendar_Birthdays.png -------------------------------------------------------------------------------- /Google Calendar_Birthdays_v2.gs: -------------------------------------------------------------------------------- 1 | /* 2 | * Отображение возраста контактов в Гугл календаре в день их рождения 3 | * Displaying birthday and age in Google's Calendar 4 | * (c) 2022 Mikhail Shardin https://shardin.name/ 5 | * 6 | * Инструкции как пользоваться: https://habr.com/ru/post/683188/ 7 | * Актуальная версия: https://github.com/empenoso/Google-Apps-Script/ 8 | * 9 | * Этот скрипт модификация моей версии 2019 года: https://habr.com/ru/post/481858/ 10 | * 11 | * Спасибо @Sergey_050krd (это ссылка на телеграм) за склонение год, лет, года и создание комментариев. 12 | * 13 | */ 14 | 15 | // Глобальные переменные 16 | var contactsCal; 17 | var defaultCal; 18 | var now; 19 | var fromDate; 20 | var toDate; 21 | var events; 22 | 23 | // Инициализация 24 | (function () { 25 | contactsCal = CalendarApp.getCalendarById('addressbook#contacts@group.v.calendar.google.com'); 26 | 27 | // Создаем события в календаре по умолчанию 28 | defaultCal = CalendarApp.getDefaultCalendar(); 29 | 30 | // Или создаем события в любом другом календаре 31 | // var defaultCal = CalendarApp.getCalendarById('regrncqXXXXXXp07eihepag74@group.calendar.google.com'); 32 | 33 | // Устанавливаем время конкретно для своего региона, например для Москвы 'Europe/Moscow'. Вы можете выбрать для себя свой часовой пояс http://joda-time.sourceforge.net/timezones.html 34 | now = new Date(); 35 | fromDate = new Date(now.getTime()); 36 | toDate = new Date(now.getTime() + 31 * (1000 * 60 * 60 * 24)); // + 31 дней от текущей даты 37 | Logger.log('С даты: ' + Utilities.formatDate(fromDate, 'Asia/Yekaterinburg', 'MMMM dd, yyyy HH:mm:ss Z')); 38 | Logger.log('По дату: ' + Utilities.formatDate(toDate, 'Asia/Yekaterinburg', 'MMMM dd, yyyy HH:mm:ss Z')); 39 | events = contactsCal.getEvents(fromDate, toDate); 40 | Logger.log('Найдено событий: ' + events.length); 41 | })(); 42 | 43 | // Дни рождения 44 | function birthdayAgeToCalendar() { 45 | for (var i in events) { 46 | Logger.log('birthdayAgeToCalendar. Дни рождения. Найдено: ' + events[i].getTitle()); 47 | var name = events[i].getTitle().split(" – день рождения")[0]; 48 | var contacts = ContactsApp.getContactsByName(name); 49 | // Logger.log('birthdayAgeToCalendar. Дни рождения. Name: ' + name); 50 | 51 | for (var c in contacts) { 52 | var bday = contacts[c].getDates(ContactsApp.Field.BIRTHDAY); 53 | var bdayMonthName, bdayYear, bdayDate; 54 | try { 55 | bdayMonthName = bday[0].getMonth(); 56 | bdayDay = bday[0].getDay() 57 | bdayYear = bday[0].getYear(); 58 | bdayDate = new Date(bdayMonthName + ' ' + bdayDay + ', ' + bdayYear); 59 | // Logger.log('birthdayAgeToCalendar. bdayDate: ' + bdayMonthName + ' ' + bdayDay + ', ' + bdayYear); 60 | } catch (error) {} 61 | 62 | var years = parseInt(new Date().getFullYear()) - bdayYear; 63 | Logger.log('birthdayAgeToCalendar. Дни рождения. ' + name + ', ' + years + ' ' + text(years) + '.'); 64 | } 65 | 66 | // Заголовок уведомления для дней рождения 67 | // Если задан номер мобильного телефона 68 | try { 69 | // Получаем номер телефона контакта для дней рождения. Необходимо чтобы у контакта (именинника) он был записан в формате +7 918 123-45-67 и обязательно стоял ярлык мобильный или мобильное устройство 70 | var contacts = ContactsApp.getContactsByName(name); 71 | var phones = contacts[0].getPhones(ContactsApp.Field.MOBILE_PHONE); // https://developers.google.com/apps-script/reference/contacts/field?hl=en 72 | 73 | var event = defaultCal.createAllDayEvent(name + " – день рождения, " + years + " " + text(years), 74 | new Date(bdayMonthName + ' ' + bdayDay + ', ' + new Date().getFullYear()), { 75 | // Устанавливаем локацию для дней рождения (можно отредактировать под себя) 76 | location: "Пермь", 77 | // Устанавливаем описание события для дней рождения (можно отредактировать под себя) 78 | description: "Сегодня " + name + " празднует день рождения - " + years + " " + text(years) + "!!!\n\nС Днём Рождения! 🎂🎁🙂🎈💃🕺\n☎️ " + phones[i].getPhoneNumber() + "" 79 | }); 80 | // Если мобильного телефона нет или указан в неправильном формате 81 | } catch (e) { 82 | e = e.message.replace(/\s/g, '+').replace(/\'/g, '') 83 | console.log(`birthdayAgeToCalendar. Мобильного телефона нет или указан в неправильном формате, пропускаем в ${new Date().toLocaleTimeString()} с ошибкой: "https://www.google.ru/search?ie=UTF-8&q=javascript+${e}".`) 84 | var event = defaultCal.createAllDayEvent(name + " – день рождения, " + years + " " + text(years), 85 | new Date(bdayMonthName + ' ' + bdayDay + ', ' + new Date().getFullYear()), { 86 | // Устанавливаем локацию для дней рождения (можно отредактировать под себя) 87 | location: "Пермь", 88 | // Устанавливаем описание события для дней рождения (можно отредактировать под себя) 89 | description: "Сегодня " + name + " празднует день рождения - " + years + " " + text(years) + "!!!\n\nС Днём Рождения! 🎂🎁🙂🎈💃🕺" 90 | }); 91 | } 92 | 93 | // Устанавливаем любой цвет для события дней рождения 94 | // event.setColor(CalendarApp.EventColor.RED); 95 | 96 | // Устанавливаем время уведомлений для дней рождения 97 | event.addPopupReminder(660); // В день события в 11:00 98 | event.addPopupReminder(0 - 24 * 60); // В день события в 00:00 99 | event.addPopupReminder(24 * 60 * 1 - 9 * 60); // За день в 09:00 100 | // event.addPopupReminder(24 * 60 * 2 - 9 * 60); // За 2 дня в 09:00 101 | } 102 | logToDrive(); //создаем файл лога на Гугл диске 103 | } 104 | 105 | // Годовщины или юбилеи 106 | function anniversaryAgeToCalendar() { 107 | for (var i in events) { 108 | Logger.log('anniversaryAgeToCalendar. Юбилеи. Найдено: ' + events[i].getTitle()); 109 | var name = events[i].getTitle().split("Юбилей у пользователя ")[1]; 110 | var contacts = ContactsApp.getContactsByName(name); 111 | Logger.log('anniversaryAgeToCalendar. Юбилеи. Name: ' + name); 112 | 113 | for (var c in contacts) { 114 | var bday = contacts[c].getDates(ContactsApp.Field.ANNIVERSARY); 115 | var bdayMonthName, bdayYear, bdayDate; 116 | try { 117 | bdayMonthName = bday[0].getMonth(); 118 | bdayDay = bday[0].getDay() 119 | bdayYear = bday[0].getYear(); 120 | bdayDate = new Date(bdayMonthName + ' ' + bdayDay + ', ' + bdayYear); 121 | // Logger.log('birthdayAgeToCalendar. bdayDate: ' + bdayMonthName + ' ' + bdayDay + ', ' + bdayYear); 122 | } catch (error) {} 123 | 124 | var years = parseInt(new Date().getFullYear()) - bdayYear; 125 | Logger.log('birthdayAgeToCalendar. Юбилеи. ' + name + ', ' + years + ' ' + text(years) + '.'); 126 | } 127 | 128 | // Заголовок уведомления для годовщин, юбилеев 129 | try { 130 | var event = defaultCal.createAllDayEvent("Сегодня юбилей у " + name + ", " + years + " " + text(years), 131 | new Date(bdayMonthName + ' ' + bdayDay + ', ' + new Date().getFullYear()), { 132 | // Устанавливаем локацию для говщин, юбилеев (можно отредактировать под себя) 133 | location: "Пермь", 134 | // Устанавливаем описание события для дней рождения (можно отредактировать под себя) 135 | description: "Сегодня юбилей у " + name + " - " + years + " " + text(years) + "!!!\n\nС памятной датой!\n☎️ " 136 | }); 137 | 138 | // Устанавливаем время уведомлений для говщин, юбилеев 139 | event.addPopupReminder(0 - 24 * 60); // В день события в 00:00 140 | event.addPopupReminder(24 * 60 * 1 - 9 * 60); // За день в 09:00 141 | // event.addPopupReminder(24 * 60 * 2 - 9 * 60); // За 2 дня в 09:00 142 | } catch (e) { 143 | e = e.message.replace(/\s/g, '+').replace(/\'/g, '') 144 | console.log(`anniversaryAgeToCalendar. Юбилея или особой даты нет у пользователя нет, пропускаем в ${new Date().toLocaleTimeString()} с ошибкой: "https://www.google.ru/search?ie=UTF-8&q=javascript+${e}".`) 145 | } 146 | 147 | // Устанавливаем любой цвет для события говщин, юбилеев 148 | // event.setColor(CalendarApp.EventColor.RED); 149 | } 150 | logToDrive(); //создаем файл лога на Гугл диске 151 | } 152 | 153 | // Склоняем окончание согласно возраста (лет, год, года) для дней рождения 154 | function text(age) { 155 | var years; 156 | count = age % 100; 157 | if (count >= 5 && count <= 20) { 158 | years = 'лет'; 159 | } else { 160 | count = count % 10; 161 | if (count == 1) { 162 | years = 'год'; 163 | } else if (count >= 2 && count <= 4) { 164 | years = 'года'; 165 | } else { 166 | years = 'лет'; 167 | } 168 | } 169 | return years; 170 | } 171 | 172 | // Автоматически создаем новые триггеры для запуска 173 | function TriggersCreateTimeDriven() { 174 | // Удаляет все триггеры в текущем проекте 175 | var triggers = ScriptApp.getProjectTriggers(); 176 | for (var i = 0; i < triggers.length; i++) { 177 | ScriptApp.deleteTrigger(triggers[i]); 178 | } 179 | 180 | // Теперь создаем для дней рождения 181 | ScriptApp.newTrigger("birthdayAgeToCalendar") 182 | .timeBased() 183 | .onMonthDay(1) // день месяца 184 | .atHour(1) // час 185 | .create(); 186 | 187 | // Теперь создаем для годовщин, юбилеев 188 | ScriptApp.newTrigger("anniversaryAgeToCalendar") 189 | .timeBased() 190 | .onMonthDay(1) // день месяца 191 | .atHour(2) // час 192 | .create(); 193 | } 194 | 195 | function logToDrive() { //создаем файл лога на диске 196 | var id = ScriptApp.getScriptId(); 197 | var name = DriveApp.getFileById(id).getName(); 198 | // определяем имя папки - начало 199 | var file = DriveApp.getFileById(id); 200 | var folders = file.getParents(); 201 | while (folders.hasNext()) { 202 | var folder_name = folders.next().getName(); 203 | Logger.log("logToDrive. Имя папки: " + folder_name) 204 | } 205 | // определяем имя папки - конец 206 | var fileName = name + "_GoogleAppsLog.txt"; 207 | try { 208 | var dir = DriveApp.getFoldersByName(folder_name).next(); //если в какой-то папке 209 | } catch (error) { 210 | var dir = DriveApp.getRootFolder(); //если корень диска 211 | } 212 | 213 | var files = dir.getFiles(); 214 | while (files.hasNext()) { 215 | var file = files.next(); 216 | Logger.log("logToDrive. Файлы в папке: " + file.getName()) 217 | if (file.getName() === fileName) { 218 | file.setTrashed(true); //удаляем предыдущий лог файл 219 | break; 220 | } 221 | } 222 | var file = dir.createFile(fileName, Logger.getLog()); //создаем лог файл 223 | } 224 | -------------------------------------------------------------------------------- /Google Calendar_Birthdays_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/empenoso/Google-Apps-Script/df76d22855e6f500dad3a062c1139efe67e7e6dd/Google Calendar_Birthdays_v2.png -------------------------------------------------------------------------------- /How to create multiple documents based on a single template using a script inside Google Sheets.gs: -------------------------------------------------------------------------------- 1 | // Иногда бывает необходимо создать множество повторяющихся документов, которые отличаются лишь номером, датой и ещё парой текстовых строк. Очень грустно тратить на их создание своё время - ведь требуется совершить множество одинаково повторяющихся действий. Ещё можно понять затраты времени на создание 5 документов, но если их надо создать, например 500 штук? 2 | // А ещё эта задача может усложнится за счёт необходимости вставки каких либо данных, которые надо сначала найти в интернете. Например, вставлять данные о погоде на дату создания документа. 3 | // К счастью, гугл таблицы могут упростить процесс создания однотипных копий с помощью шаблона. В этой статье покажу как можно создать неограниченное число копий на основе одного шаблона с помощью гугл скрипта внутри гугл таблицы. 4 | 5 | // https://habr.com/ru/articles/728840/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Mikhail Shardin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | My Google Apps Script :star:: 2 | 3 | 1\. [Birthdays and anniversaries with dates for your calendar](#google-calendar_birthdaysgs-underage) 4 | 5 | 2\. [A child’s age in months and years, with a monthly reminder v2](#google-calendar_a-childs-age_v2gs-baby) 6 | 7 | 3\. [A child’s age in months and years, with a monthly reminder v1](#google-calendar_a-childs-age_v1gs-baby) 8 | 9 | Read this in other languages: [на русском языке](README.ru.md). 10 | 11 | _____________ 12 | 13 | # Google Calendar_Birthdays.gs :underage: 14 | 15 | *[Google Apps Script Google Calendar_Birthdays.gs](Google%20Calendar_Birthdays.gs) that creates events (birthdays and anniversaries), indicating the past years in the calendar.* 16 | 17 | As a user of an Android phone, I was not always happy with the fact that my calendar displayed the birthdays of contacts without indicating the age of a person. The same situation was with the anniversaries of contacts - there seems to be an anniversary, but it is not clear how many years the anniversary is for. Looking through your contacts' details, finding the year of birth or the date of the anniversary, and then figuring the math - there has never been time for this. I decided to simplify my life and wrote a Google Apps Script, which first, searches for these events in a special calendar that displays these events by default. And then, in the second step, it calculates the age for specific contacts and creates events in the main calendar. This script was published on the [Google Sheets Telegram channel (in Russian)](https://t.me/google_sheets/365). 18 | 19 | ![](Google%20Calendar_Birthdays.png) 20 | 21 | # Google Calendar_A child’s age_v2.gs :baby: 22 | 23 | *[Google Apps Script](Google%20Calendar_A%20child’s%20age_v2.gs) is great for all young fathers - it shows how many months and years the child is old, with a monthly reminder.* 24 | 25 | This is a code that makes life easier for young fathers - because while all the grandmothers perfectly remember their grandson’s/granddaughter’s birthday and congratulate on this event every month - I could not keep it in my memory. I decided to slightly automate the process and at the same time figure out how to work with dates in Google Apps Script. And of course, to make this reminder appear in advance, and not on the baby’s birthday! 26 | 27 | ![](Google%20Calendar_A%20child’s%20age_v2.png) 28 | 29 | # Google Calendar_A child’s age_v1.gs :baby: 30 | 31 | *[Google Apps Script](Google%20Calendar_A%20child’s%20age_v1.gs) is great for all young fathers - it shows how many months and years the child is old, with a monthly reminder.* 32 | 33 | This is a code that makes life easier for young fathers - because while all the grandmothers perfectly remember their grandson’s/granddaughter’s birthday and congratulate on this event every month - I could not keep it in my memory. I decided to slightly automate the process and at the same time figure out how to work with dates in Google Apps Script. And of course, to make this reminder appear in advance, and not on the baby’s birthday! This script was published on the [Google Sheets Telegram channel (in Russian)](https://t.me/google_sheets/435). 34 | 35 | ![](Google%20Calendar_A%20child’s%20age_v1.png) 36 | -------------------------------------------------------------------------------- /README.ru.md: -------------------------------------------------------------------------------- 1 | Мои гугл скрипты :star:: 2 | 3 | 1\. [Дни рождения и юбилеи с датами в календарь](#google-calendar_birthdaysgs-underage) 4 | 5 | 2\. [Месяцы и годы ребенка, ежемесячная напоминалка v2](#google-calendar_a-childs-age_v2gs-baby) 6 | 7 | 3\. [Месяцы и годы ребенка, ежемесячная напоминалка v1](#google-calendar_a-childs-age_v1gs-baby) 8 | 9 | Read this in other languages: [English](README.md). 10 | 11 | __________ 12 | 13 | # Google Calendar_Birthdays.gs :underage: 14 | *[Google Apps Script Google Calendar_Birthdays.gs](Google%20Calendar_Birthdays.gs), который создает события (дни рождения и юбилеи) с указанием прошедших лет в календаре.* 15 | 16 | Меня, как пользователя телефона с системой Android, всегда не очень устраивал тот факт, что в моём календаре были обозначены дни рождения контактов, но без указания возраста человека. 17 | Также и с юбилеями контактов - вроде бы юбилей есть, а сколько времени прошло с этого события непонятно. Переходить в сам контакт и смотреть год рождения или дату юбилея, а потом что-то рассчитывать - на это времени никогда не было. Решил сам себе упростить жизнь и написал Google Apps Script, который сначала ищет эти события в специальном календаре, который по умолчанию выводит эти события. А затем на втором шаге рассчитывает возраст для конкретных контактов и уже создает события в основном календаре. Этот скрипт был опубликован в [Telegram-канале Google Таблицы](https://t.me/google_sheets/365). 18 | 19 | ![](Google%20Calendar_Birthdays.png) 20 | 21 | # Google Calendar_A child’s age_v2.gs :baby: 22 | Если у вас есть дети, один или несколько, то вам будет интересно это приложение *[Google Apps Script](Google%20Calendar_A%20child’s%20age_v2.gs)*. Этот скрипт ежемесячно создаёт событие в гугл календаре, в котором точно указан возраст ребенка, а также указаны значимые события из жизни родителей. С этим скриптом вам не придётся помнить даты, но вам придёт оповещение стандартными средствами гугл календаря. Вот результат работы этого скрипта: 23 | 24 | ![](Google%20Calendar_A%20child’s%20age_v2.png) 25 | 26 | 27 | # Google Calendar_A child’s age_v1.gs :baby: 28 | *[Google Apps Script](Google%20Calendar_A%20child’s%20age_v1.gs) для всех молодых отцов - сколько месяцев и годов ребенку отроду, ежемесячная напоминалка.* 29 | 30 | Это код, который облегчает жизнь молодым отцам - ведь в то время как все бабушки отлично помнят день рождения своего внука/внучки и поздравляют с этим событием ежемесячно - мне никак не удавалось удержать это в памяти. Решил слегка автоматизировать процесс и заодно разобраться как работать с датами в Google Apps Script. И конечно же сделать, чтобы эта напоминалка появлялась заблаговременно, а не в день рождения малыша! Этот скрипт был опубликован в [Telegram-канале Google Таблицы](https://t.me/google_sheets/435). 31 | 32 | ![](Google%20Calendar_A%20child’s%20age_v1.png) 33 | --------------------------------------------------------------------------------