iCal занимает день выезда? Сдвиг на сутки, который крадёт ваши ночи
Календарь синхронизируется исправно, а день выезда на другой площадке занят. Почему невключающий DTEND и часовые пояса в iCal тихо съедают ночь, которую можно было продать.

Гость съехал из моей квартиры в Ташкенте в субботу, в 11 утра. К часу дня квартира была убрана и готова к заезду. Кто-то попытался забронировать именно эту субботу на Booking.com — и получил «нет мест». Ночь ушла впустую, а я не понимал почему: календари синхронизировались идеально. Просто даты были сдвинуты ровно на сутки.
Об этой ошибке не предупреждает никто. iCal-фид свежий, отметки времени актуальные, каждое обновление проходит — а площадка всё равно блокирует не тот день. Разберём, почему так выходит, как за две минуты проверить, что это происходит у вас, и как починить каждую из причин.
Ошибка, которая прячется за рабочей синхронизацией
Большинство проблем с календарём — про устаревший фид: сброшенная ссылка, фид, который площадка тихо отключила после череды неудачных запросов, импорт с надписью «Последняя синхронизация: никогда». Если симптом такой — вам в соседний разбор о том, почему календарь Airbnb перестаёт синхронизироваться: семь причин, и все про то, что фид не обновляется.
Здесь — обратная ситуация. Фид обновляется нормально. Отметка «Последний импорт» — двадцатиминутной давности. Любая бронь с Airbnb появляется на Booking.com в пределах окна опроса. И всё же одна конкретная ночь — почти всегда день выезда, иногда ночь перед заездом — показывается занятой, хотя квартира заведомо пуста.
Сообщения об ошибке вы не получите. Вы получите календарь, который уверенно и молча ошибается ровно на сутки. Замечаешь это только когда гость пишет «у вас занято» на дату, которую вы знаете как свободную, — или когда сам идёшь выяснять, почему ходовая суббота так и не продалась.
Почему день выезда обязан быть свободным
iCal — не размытый формат, а стандарт RFC 5545, и он строго описывает, как работает диапазон дат. Для события «на весь день» бронь — это полуоткрытый интервал [DTSTART, DTEND). DTSTART входит. DTEND — нет. Это утро уже после последней ночи.
Возьмём бронь на три ночи: заезд 10 июля, выезд 13-го. Гость ночует с 10-го по 12-е — три ночи. Правильный блок в iCal выглядит так:
BEGIN:VEVENT
DTSTART;VALUE=DATE:20260710
DTEND;VALUE=DATE:20260713
SUMMARY:Reserved
END:VEVENT
Обратите внимание: DTEND:20260713, а не 20260712. 13-е — день выезда, и по правилу невключающего конца он свободен: новый гость может заехать в тот же день после обеда. Это не лазейка, а штатная работа сцепленных броней. Площадки моделируют это правильно: и Airbnb, и Booking.com считают день выезда доступным для заезда в тот же день — именно это и позволяет делать плотную пересменку на ходовые выходные.
Значит, если день выезда показывается занятым, что-то между исходной площадкой и принимающей перестало уважать невключающий DTEND. Это случается двумя путями.
Причина 1: фид, который блокирует день выезда
Первый сбой — «включающий» DTEND. Где-то в цепочке ночь, которая должна быть свободной, засчитывается как занятая.
Проявляется двояко. Либо ошибается генератор фида — самописный cron или устаревший channel manager пишет DTEND:20260714 (на сутки дальше нужного) или отдаёт отдельный блок на день выезда, — либо импортёр трактует DTEND как включающий и блокирует по 13-е, хотя в фиде стоит 20260713.
На практике чаще виноват генератор: крупные площадки правило невключающего конца соблюдают. Если вы синхронизируете Airbnb прямо в Booking.com без промежуточного слоя, на это почти не натыкаешься. Натыкаешься, когда в цепочке есть третий инструмент — ваш скрипт, небольшая PMS, экспорт из таблицы в iCal, — который ошибается на единицу. Классика: человек рассуждает «бронь с 10-го по 13-е» и пишет DTEND:20260713, имея в виду включительно, тогда как iCal прочитает это же значение как исключающее и освободит 13-е. Перебор или недобор зависит целиком от того, какая модель была в голове у автора, — и формат ни о чём его не предупредит.
Итог — реальные деньги: каждый ошибочно занятый день выезда — это пересменка в тот же день, которую нельзя продать. На объекте, который в сезон идёт сцепленными бронями, это по ночи в неделю — впустую и без единого сообщения об ошибке.
Причина 2: часовые пояса сдвигают ночь не туда
Второй сбой тоньше, и для хостов из разных стран он встречается куда чаще. Он идёт от фидов, которые отдают даты как DATE-TIME, а не как событие на весь день (DATE).
У события на весь день нет часового пояса: 20260713 — это 13-е в любой точке планеты. Но некоторые фиды отдают бронь со временем суток и поясом — или, хуже, приведённую к UTC:
DTSTART:20260713T000000Z
DTEND:20260716T000000Z
Буква Z означает UTC. Теперь принимающая площадка должна перевести это в своё местное время, прежде чем решить, на какой календарный день попадает блок. Блок, который начинается в 20260713T000000Z — полночь по UTC, — из часового пояса на пять часов западнее превращается в 19:00 12-го июля. Отбросьте время — и вы только что заняли 12-е, ночь, которая должна была быть свободной. Блок сполз на сутки назад. Теперь занятой показывается ночь перед заездом гостя.
Сдвиньте объект восточнее UTC — и поедет в другую сторону. Выезд, который должен был освободить утро, наоборот оставит ночь занятой, потому что переведённое время округлится до следующего дня. Причина та же, симптом обратный.
Сверху добавляется переход на летнее время с его сдвигом на час. Бронь, которая зимой ложилась на границу идеально, может уехать на сутки в те недели, когда исходная и принимающая стороны на разном расписании перехода: Европа и США переводят часы в разные даты, так что каждую весну и осень есть окно в две-три недели, когда событие DATE-TIME у полуночи перескакивает. Если ваш сдвиг на сутки появляется только часть года — вот почему.
Подсказка — в самом фиде: значение DATE-TIME (в нём есть T, часто Z на конце или префикс TZID=) зависит от часового пояса и есть главный подозреваемый. Обычный VALUE=DATE из восьми цифр без T к этому невосприимчив.
Как убедиться, что это происходит у вас
Гадать не нужно. Две минуты с сырым фидом всё решают.
- Возьмите ссылку на iCal-экспорт исходной площадки — ту, что копируется из Airbnb (Calendar → Sync calendars → Export) или Booking.com (Calendar & Pricing → Sync calendars → Export).
- Вставьте её прямо в браузер. Получите файл
.icsили простыню текста, начинающуюся сBEGIN:VCALENDAR. Если вместо этого открылась HTML-страница с ошибкой — у вас устаревание, а не даты: возвращайтесь к чек-листу по «зависшему» фиду. - Найдите
VEVENTтой брони, чьи реальные даты вы помните точно. Прочитайте еёDTSTARTиDTEND.
Теперь расшифруйте увиденное:
| Как выглядит строка фида | Что это значит | Риск сдвига |
|---|---|---|
DTSTART;VALUE=DATE:20260710 | На весь день, без часового пояса | Нет — безопасная форма |
DTEND;VALUE=DATE:20260713 | День выезда, невключающий (верно) | Нет |
DTEND;VALUE=DATE:20260712 | Последняя ночь, а не день выезда | Включающая ошибка — занимает пересменку |
DTSTART:20260710T140000Z | Время по UTC | Высокий — переводится по поясу |
DTSTART;TZID=...:20260710T140000 | Время в именованном поясе | Средний — зависит от импортёра |
Дальше сверьтесь с принимающей стороной: откройте спорный день в календаре другой площадки. Если фид говорит, что день выезда свободен (DTEND — дата выезда, на весь день), а принимающая показывает его занятым — виноват импортёр. Если же неверный день зашит уже в самом фиде — виноват источник или промежуточный инструмент.
Как починить каждую причину
Починка зависит от того, какое звено цепочки ошибается, и — что важнее — управляете ли вы им.
Если вы управляете генератором фида (свой скрипт, самостоятельный экспортёр): отдавайте события на весь день с VALUE=DATE, а DTEND ставьте на день выезда, а не на последнюю ночь. Никогда не отдавайте время суток для блока на весь день. Одна эта правка убивает обе причины в источнике: нечего переводить по поясам, негде ошибиться на единицу.
Если источник отдаёт DATE-TIME, а изменить его вы не можете: поставьте между площадками нормализующий слой. Он принимает «грязный» фид, переписывает каждую бронь в событие на весь день (VALUE=DATE) в часовом поясе самого объекта и отдаёт остальным площадкам уже чистый фид. Именно это на каждом обновлении делает iCal-инструмент вроде RentTools: он привязывает каждый блок к местному календарному дню объекта раньше, чем кто-то ниже по цепочке успеет прочитать его не так. Рулетка с поясами через границы заканчивается.
Если импортёр трактует DTEND как включающий и поправить код площадки вы не можете (а вы не можете) — есть два пути: добавить буферный день на уборку, чтобы день выезда блокировался намеренно (см. буферные дни), или пустить поток через промежуточный слой, который это компенсирует. Буфер прячет симптом, а не лечит его — нормально, пока не настанет день, когда эту пересменку хочется продать.
После любой починки проверяйте так же, как диагностировали: заберите фид, убедитесь, что DTEND — это дата выезда на весь день, и посмотрите, что принимающий календарь показывает день выезда свободным. Не верьте, что сработало, — смотрите на ячейку.
Во что на самом деле обходится сдвиг на сутки
Ради чего вообще тратить время на диагностику: эта ошибка невидима и повторяется. Она стоит не одной ночи однажды — она стоит ночи на каждой задетой брони, каждый раз, пока вы её не найдёте.
Вот объект с плотной пересменкой по базовой ставке 120 $, у которого ошибка блокирует две пересменки в месяц:
| Сценарий | Потеряно ночей в месяц | Потеря в месяц | Потеря в год |
|---|---|---|---|
| 2 занятых дня выезда, база 120 $ | 2 | 240 $ | 2 880 $ |
| Сезонный поток, 1 ночь в неделю | 4 | 480 $ | (по сезону) |
| Сдвиг на ночь перед заездом, 1 в месяц | 1 | 120 $ | 1 440 $ |
Это не возвраты, которые видно в отчёте, — это брони, которых не случилось: спрос упёрся в «нет мест» и ушёл к соседнему объекту. Арифметика приблизительная, потому что зависит от того, как часто ваши окна — это пересменка в тот же день, но направление ясно: повторяющаяся утечка по ночи на объекте с реальным спросом на пересменку — это четырёхзначная сумма в год, и она нигде не всплывает как проблема, на которую можно ткнуть пальцем.
И она складывается с тем, что стоит рядом. Ошибочно занятый день выезда — это пересменка, которую нельзя продать; ошибочно освобождённый день выезда — это как получают двойное бронирование. Одно и то же правило невключающего DTEND, оба направления сбоя — и узнать, на каком вы, можно только прочитав фид.
Особое мнение
Если у вас больше одной площадки и вы ни разу не открывали свой сырой .ics в браузере — сделайте это на этой неделе. Не потому, что всё сломано (может, и нет), а потому, что это единственный сбой календаря, который стоит денег при нулевом сигнале. Устаревший фид рано или поздно заявит о себе: гость пожалуется, дата не обновится, отметка времени остынет. Сдвиг на сутки просто молча превращает ваши лучшие пересменки в «нет мест» и уводит бронь к другому. Пятнадцать секунд на проверку того, что фид отдаёт VALUE=DATE и невключающий день выезда DTEND, — самый дешёвый аудит выручки, который вы когда-либо проведёте.
Частые вопросы
Почему день, когда гость выезжает, показывается занятым для новой брони?
Потому что что-то в цепочке синхронизации считает день выезда занятым. По правилам iCal день выезда — это невключающий
DTEND: утро уже после последней ночи, оно должно быть доступно для заезда в тот же день. Если он показывается занятым, либо генератор фида записал диапазон «по-включающему», либо перевод часового пояса сдвинул блок на сутки.Что значит, что
DTENDневключающий?Это значит, что дата конца в бронь не входит. Бронь с
DTSTART:20260710иDTEND:20260713покрывает три ночи — на 10-е, 11-е и 12-е — и оставляет 13-е свободным. Многие читают20260713как «занято по 13-е включительно», но формат говорит обратное. Именно это расхождение — самый частый источник ошибок на сутки в календаре.Календарь синхронизируется вовремя, но блокирует не те даты. Это то же самое, что устаревший фид?
Нет, и для починки разница важна. Устаревший фид — это про свежесть: импорт перестал обновляться, и чинится это починкой ссылки или повторным добавлением импорта. Фид с неверными датами обновляется нормально — ошибочны даты внутри. Сначала проверьте отметку «Последний импорт»: свежая отметка плюс неверные даты — это сдвиг на сутки, а не устаревание.
Как понять, что в моём iCal-фиде — даты или дата-время?
Вставьте ссылку на экспорт в браузер и посмотрите на
VEVENT. Если видитеDTSTART;VALUE=DATE:20260710— восемь цифр, безT— это событие на весь день, к часовым поясам невосприимчивое. Если после даты стоитTи время, а тем болееZна конце — этоDATE-TIME, и где-то ниже по цепочке происходит перевод пояса.Может ли переход на летнее время и правда сдвинуть бронь на сутки?
Только для фидов с
DATE-TIMEу самой полуночи и только в недели, когда исходный и принимающий регионы на разном расписании перехода. Европа и Северная Америка переводят часы в разные даты, поэтому каждую весну и осень есть короткое окно, когда событие у полуночи попадает не на тот календарный день. СобытияVALUE=DATEна весь день это не затрагивает никогда.Решает ли это channel manager или промежуточный слой?
Может решить — если слой приводит фиды к событиям на весь день в местной дате перед тем, как отдать дальше. Это снимает неоднозначность пояса для всех ниже по цепочке. Не поможет, если слой сам отдаёт
DATE-TIMEили ошибается на единицу: лечит не наличие инструмента, а правильная работа с датами. Прочитайте отданный фид и убедитесь, что в нёмVALUE=DATE.Буферный день — это решение или костыль?
Костыль, но полезный. Буфер в один день блокирует день выезда намеренно, поэтому сдвиг, который тоже его блокирует, становится невидимым — вы эту ночь и не продавали. Проблема возвращается в тот миг, когда вы убираете буфер ради ходовой пересменки, так что относитесь к буферу как к прикрытию, а не лечению, и всё равно чините работу с датами.
Почему иногда блокируется ночь перед заездом, а не день выезда?
Направление зависит от того, в какую сторону часовой пояс смещает дату. Блок, приведённый к UTC, из пояса западнее UTC уезжает раньше и может занять ночь перед заездом; из пояса восточнее UTC — уезжает позже и оставляет занятой ночь выезда. Причина одна, симптом обратный — и то и другое лечится привязкой блока к местной дате объекта.
Читать дальше
iCal checkout day blocked? The off-by-one bug eating your nights
Your calendar syncs fine but the checkout day shows as booked on the other platform. Why iCal's exclusive DTEND and timezone drift quietly block a night you could sell.
Airbnb calendar not syncing? 7 reasons your iCal feed goes stale
Airbnb calendar not syncing with Booking.com? The 7 reasons an iCal feed goes stale, the one timestamp that flags each, and the exact fix for all seven.
Channel manager break-even math: when paying $40 a month actually pays back
When does a paid channel manager pay for itself? Worked break-even math at 1, 3, 8, and 15 properties — plus the failure cost most hosts forget to price in.
Free property-management tools for short-term rental hosts in 2026
A 2026 roundup of free property-management software for Airbnb and Booking.com hosts. Managed-free, self-host-free, DIY combos, and where each one breaks.
Setting buffer days right: stop back-to-back cleaning chaos
How to pick the right cleaning buffer days for short-term rentals. The revenue-vs-quality tradeoff, the math, and a per-property rule that scales.
Avoiding double bookings: the only host cheat sheet you need
A cheat sheet for short-term rental hosts to prevent double bookings. Sync intervals, buffer days, manual-entry rules, and the 24-hour pre-arrival audit.
Comments
Sign in to comment.
- No comments yet.