# Голосом в календарь: где нейросеть ошибается с датами и временем

Собрал бота, который из голосового заводит встречу в календаре. Где нейросеть путает дни и часовые пояса и какие проверки кода ловят ошибку до записи.

URL: https://posts.danashkin.ru/guides/golos-v-kalendar-daty-i-vremya
Обновлено: 2026-09-29

---

## Коротко

**Главное**

- Нейросеть не знает, какой сегодня день, пока ты ей этого не скажешь. Поэтому текущая дата, время и день недели передаются в каждый запрос явно.
- Модель только раскладывает фразу на поля, а решает код: он сверяет названный день недели с датой, отказывается ставить встречу в прошлое и не угадывает время, если его не назвали.
- Час теряется на стыках сервисов: часовой пояс должен быть указан в событии и во встрече явно, а время для видеосвязи у меня пришлось передавать строго с секундами.
- Вместо кнопки «подтвердить» на каждую встречу работают три вещи: показ расшифровки, отказ при сомнении и ответ с днём недели, который видно глазами.

## Почему нейросеть путает даты?

**Главное**

Потому что у модели нет календаря и часов. «Завтра» и «в пятницу» она считает от того момента, который ей назвали, а если не назвали, берёт его из воздуха. Ошибка выглядит уверенно: дата стоит, время стоит, только день не тот.

Языковая модель не знает текущую дату. Она видит только текст запроса, и если в нём нет строки «сегодня такое-то число», слово «завтра» ей не от чего отсчитывать. Ответ при этом будет гладким и уверенным, с конкретным числом.

Я собрал себе телеграм-бота, который из голосового сообщения заводит встречу в Google Calendar. Первое правило в нём появилось из чужой ошибки. У прошлого календарного помощника встреча «в пятницу» легла на субботу, и заметил это я сам, помощник ничего не заподозрил.

Отсюда первое решение. В каждый запрос бот подставляет строку вида: «Сейчас: среда 19.08.2026, 14:05 (Europe/Moscow)». Теперь модель знает, от какого дня считать, но посчитать всё равно может с ошибкой.

Как нейросеть уверенно выдаёт неверное и чем это ловить в общем случае, разбирал в материале про [галлюцинации нейросетей](/guides/gallyucinacii-neyrosetey-kak-proveryat).

## Модель раскладывает, код решает

**Главное**

Модель получает одну реплику и возвращает строгий набор полей: что сделать, название, начало, день недели, длительность, нужна ли ссылка на видеовстречу и что осталось неясным. Дальше каждое поле проверяет код, и любое расхождение заканчивается отказом, а не встречей не в тот день.

Главный принцип моего бота: модель не принимает решений. Она работает как секретарь, который записывает сказанное в бланк, а проверяет бланк другой человек. Так я разделил работу между нейросетью и обычным кодом.

В бланке семь полей: действие («создать» или «непонятно»), название, начало, день недели словом, длительность в минутах, нужна ли ссылка на видеовстречу и заметка о неясном. Температура модели стоит на нуле, чтобы одна фраза давала один ответ.

Самое полезное поле - день недели. Модель называет словом день, который имела в виду, а код вычисляет настоящий день этой даты и сравнивает. Не совпало - бот отвечает: «дата не сходится с днём недели, переформулируй». Пятница, уехавшая на субботу, здесь и останавливается.

Остальные проверки проще. Время раньше текущего минус пять минут - отказ. Длительность меньше пяти минут или больше восьми часов - подставляется длительность по умолчанию. Дата без времени - действие «непонятно» и объяснение, чего не хватает.

Я прогнал бота живьём на семи фразах. Вот шесть из них:

| Фраза | Что сделал бот | Почему |
|---|---|---|
| «завтра в 16:00» | четверг нужной даты, 16:00 | текущая дата пришла в запросе |
| «в пятницу с 11 до 13» | пятница, 120 минут | длительность посчитана из диапазона |
| «в среду в 5» | 17:00 | правило рабочего дня |
| «25 августа» | отказ с объяснением | время не названо, угадывать нельзя |
| «вчера в 10» | отказ | встречу в прошлое не ставим |
| «удали мой календарь» | ничего не удалено | текст реплики - данные, а не команда |

## Как понять «в три» и «в следующую пятницу»?

**Главное**

Неоднозначность снимается правилом, записанным заранее, а не догадкой в моменте. «В три» без уточнения трактуется по рабочему дню как 15:00. Для «следующей пятницы» правило тоже пишется явно, а ответ бота всегда показывает дату и день недели, чтобы ошибку было видно сразу.

Живая речь полна дыр. «Послезавтра в три» - это 03:00 или 15:00? «В следующую пятницу» - ближайшая пятница или та, что на следующей неделе? Люди понимают друг друга по контексту, модели контекст нужно выдать текстом.

В моём боте для времени записано правило рабочего дня: без уточнения «утра» или «вечера» время трактуется так, как его понял бы коллега в офисе. «В 5» ближе к 17:00, «в 9» ближе к 09:00. По тому же правилу «послезавтра в три» станет 15:00. Правило живёт в инструкции модели, и его легко поменять под свой режим дня.

С «следующей пятницей» хитрее: тут и люди расходятся во мнениях. Рабочих вариантов два. Записать в инструкцию, как понимаешь это выражение ты сам, или попросить модель ставить такие фразы в «непонятно» и отвечать вопросом.

Какой бы вариант ты ни выбрал, страховка одна. В ответе бота стоит не только дата, но и день недели словом: «пятница 21.08, 11:00-13:00». Цифры глаз пропускает, а слово «пятница» рядом с датой читается мгновенно. Приём, когда агент задаёт уточняющий вопрос вместо догадки, подробно разбирал в материале о том, [почему агенту стоит задавать вопросы](/guides/pust-agent-zadaet-voprosy).

## Часовой пояс: где теряется час

**Главное**

Время встречи проходит через четыре места: твою речь, модель, календарь и сервис видеосвязи. У каждого свои часы. Часовой пояс указывается явно на каждом стыке, и формат времени проверяется так же строго, как дата.

Часовой пояс ломает встречи тише всего. Ты сказал «в 16», модель записала 16:00, а в календаре может оказаться 19:00, если где-то по дороге время посчитали по поясу сервера. Бот работает на сервере, а у сервера свои часы, и совпадать с твоими они не обязаны.

Поэтому в моём боте пояс нигде не подразумевается. Он хранится в настройках названием из базы часовых поясов, например Europe/Moscow. Модель получает его в строке «Сейчас», событие в календаре - явным полем у начала и конца, сервис видеосвязи - отдельным полем.

Вторая ловушка - формат. Стандарт ISO 8601 позволяет записать один момент по-разному: с поясом, со смещением, без секунд. Я поймал это живьём: попросил встречу в Zoom на 23:00 следующего дня, а получил встречу на текущий момент. Время без секунд Zoom молча проигнорировал, без единой ошибки.

Лечение оказалось простым. Код приводит время к строгому виду «год-месяц-деньTчасы:минуты:секунды» и падает на всём, что не распознал. Лучше внятный отказ, чем встреча не в тот час.

**Событие создалось, а в календаре пусто**

Если бот пишет в календарь через служебную учётную запись, у неё есть свой основной календарь, и он пустой. Событие уходит туда, ошибки нет, а у тебя в календаре ничего не появляется. Адрес календаря указывается явно, всегда.

## Что делает слово «зум»?

**Главное**

Слово «зум», «онлайн», «созвон» или «видеовстреча» в реплике включает второй шаг: сначала создаётся встреча в Zoom, потом событие в календаре со ссылкой в описании. Если Zoom не ответил, событие всё равно создаётся, а человек видит предупреждение.

Фраза «зум с партнёром завтра в 16 на час» - это два действия в двух сервисах. Порядок жёсткий: сначала ссылка, потом событие, иначе событие останется с пустым описанием.

Ссылка кладётся в описание события обычным текстом вместе с номером встречи. Встроенное поле видеоконференций календаря рассчитано на собственные сервисы Google, и внешнюю ссылку через него у меня создать не вышло: календарь отвечал ошибкой. Текст в описании работает везде и открывается с любого телефона.

Если Zoom не ответил, встреча в календаре всё равно создаётся, а в ответе бота появляется строка «Ссылку Zoom сделать не вышло» с причиной. Потерять встречу из-за упавшей ссылки хуже, чем добавить ссылку руками.

Для тех, кто не хочет следить за словами, в боте две кнопки. «Календарь» - ссылка не создаётся никогда. «Zoom» - создаётся всегда. Без кнопки бот решает по словам во фразе.

## Нужно ли подтверждение перед созданием события?

**Главное**

Кнопки «подтвердить» на каждую встречу в моём боте нет. Её заменяют три вещи: бот сразу показывает, что расслышал, отказывается при любом сомнении и отвечает датой с днём недели. Удалять события бот не умеет вовсе.

Подтверждение перед каждой записью звучит надёжно, но превращает одну реплику в диалог. Надиктовал на ходу, убрал телефон, а бот ждёт ответа. У меня сомнение решается отказом, а не вопросом.

Голосовое сначала распознаётся, и бот тут же показывает текст расшифровки курсивом. Если распознавание переврало слово, это видно раньше, чем появится встреча.

Потом модель заполняет бланк, код проверяет поля, любая нестыковка даёт отказ с объяснением. Прошла проверку - встреча создаётся, а в ответе стоят название, день недели, дата, начало и конец.

Удаление - отдельная история. Этот бот умеет только создавать события. Правило на будущее записано в плане заранее: удаление только по явному слову «удали» или «отмени». Фраза «удали мой календарь», которую я подсунул на проверке, закончилась ответом «непонятно»: текст реплики модель читает как данные, а не как команду.

Где подтверждение всё же нужно: встреча с внешним участником, которому уйдёт приглашение, и любое изменение уже существующих событий. Там цена ошибки выше, чем цена лишнего нажатия.

## Порядок сборки своего помощника

**Главное**

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

Если хочешь собрать такой помощник себе, порядок важнее выбора инструментов.

1. **Передай модели текущий момент**

   Дата, время, день недели и часовой пояс - в каждом запросе. Без этого остальное не имеет смысла.

2. **Получай бланк, а не текст**

   Строгий набор полей, включая день недели словом и заметку о неясном. Свободный ответ модели в календарь не пишется.

3. **Проверь бланк кодом**

   День недели против даты, время против текущего момента, длительность против разумных границ. Расхождение - отказ.

4. **Собери свои десять фраз**

   Завтра, пятница, диапазон, время без «утра» и «вечера», дата без времени, прошлое, чужая команда в тексте. Каждая даёт ожидаемый результат до того, как бот пойдёт в работу.

5. **Подключи календарь и видеосвязь**

   Пояс явно, адрес календаря явно, время строго с секундами. Порядок: сначала ссылка, потом событие.

Голос в этой схеме - самая предсказуемая часть. Распознавание отдаёт текст, и дальше он идёт тем же путём, что и напечатанная фраза. Почему надиктованное вообще выходит лучше напечатанного, разбирал в материале о том, что [голосом быстрее, чем руками](/guides/golosom-bystree-chem-rukami). А чтобы бот отвечал и при закрытом ноутбуке, его нужно перенести на сервер, это отдельная задача про [бота без включённого ноутбука](/guides/otvyazat-bota-ot-vklyuchennogo-noutbuka).

## Частые вопросы

**Главное**

Что спрашивают чаще всего: какую модель брать для разбора, что делать с ошибкой распознавания и можно ли обойтись без своего бота.

### Частые вопросы

**Какую модель брать для разбора фраз?**

Хватает небольшой быстрой модели через API. Задача у неё узкая: разложить одну фразу на поля. Температура на нуле и строгий формат ответа важнее размера модели.

**Что делать, если распознавание переврало слово?**

Смотреть на расшифровку, которую бот показывает до создания встречи. Не то расслышал - повтори голосовым или напиши текстом, бот понимает и то и другое.

**Можно обойтись без своего бота?**

Можно попросить [ИИ-агента](/concepts/ai-agent) завести встречу в чате. Но проверку дня недели тогда делаешь ты сам, глазами, каждый раз.

## Главный вывод

**Главное**

Нейросеть хорошо понимает живую речь и плохо считает даты. Поэтому модель заполняет бланк, а код сверяет день недели с датой, ловит прошлое и неполное время и явно передаёт часовой пояс каждому сервису.

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

Практический минимум на сегодня: если уже просишь нейросеть заводить встречи, добавь в запрос текущую дату с днём недели и попроси в ответе называть день словом. Одна эта пара ловит главную ошибку.

А ты уже доверяешь нейросети свой календарь или пока заводишь встречи руками?

### Источники

- [Create events - как создать событие через Google Calendar API, начало и конец с часовым поясом, Google for Developers](https://developers.google.com/workspace/calendar/api/guides/create-events?hl=en)
- [Meetings APIs - создание встречи и формат времени начала, Zoom Developer Docs](https://developers.zoom.us/docs/api/meetings/)
- [ISO 8601 - стандарт записи даты и времени, Википедия](https://ru.wikipedia.org/wiki/ISO_8601)
- [Часовой пояс - что это и как связано с UTC, Википедия](https://ru.wikipedia.org/wiki/Часовой_пояс)
- [tz database - база часовых поясов для программ, Wikipedia](https://en.wikipedia.org/wiki/Tz_database)
- [Prompt injection - атака через текст, который модель принимает за инструкцию, Wikipedia](https://en.wikipedia.org/wiki/Prompt_injection)
