Как сделать так, чтобы лента iCal для праздников была перенесена на соседние дни недели?

Я пытаюсь создать фид iCal (RFC 2445) для рабочих праздников, не нуждаются в ежегодных обновлениях, перечисляя праздники в соответствии с их определением, а не датами, в которые они приходятся на определенные годы.

Такие праздники, как День памяти (последний понедельник мая), конечно, не требуют особого отношения, кроме

BEGIN:VEVENT
DTSTAMP:20130210T211949Z
UID:[email protected]
DTSTART;VALUE=DATE:20130527
DTEND;VALUE=DATE:20130527
SUMMARY:Memorial Day
RRULE:FREQ=YEARLY;BYMONTH=5;BYDAY=-1MO;WKST=SU
END:VEVENT

... но когда дело доходит до праздников, привязанных к дате, таких как Новый год, как можно закодировать сдвиг дня в выходные дни 1 января?


person ecmanaut    schedule 11.02.2013    source источник


Ответы (2)


вы должны знать, что хотя календарь Google соответствует RFC2445, он устарел в соответствии с RFC5545, который сделал EXRULE устаревшим (устаревшие функции из RFC2445).

в случае Нового года в Великобритании это:

BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
PRODID:pyICSParser
BEGIN:VEVENT
DTSTART;VALUE=DATE:20070101
RRULE:FREQ=YEARLY;BYMONTH=1;BYDAY=MO,TU,WE,TH,FR;BYMONTHDAY=1,2,3;BYSETPOS=1
UID:[email protected]
DTSTAMP:19970714T170000Z
SUMMARY: new year
END:VEVENT
END:VCALENDAR

который отлично работает в календаре Google, Outlook.com(/hotmail/...), календарях Yahoo и на устройствах iOS, синхронизирующихся с Календарем Google.

ОБНОВЛЕНИЕ: к Новому году в США

это будет комбинация 2 RRULE (RFC говорит SHOULD NOT occur more than once, что, кажется, оставляет возможность 2 RRULE по событию:

RRULE:FREQ=YEARLY;BYMONTH=1;BYDAY=MO,TU,WE,TH,FR;BYMONTHDAY=1,2;BYSETPOS=1
RRULE:FREQ=YEARLY;BYMONTH=12;BYDAY=FR;BYMONTHDAY=-1

Календарь Google поддерживает его, но похоже, что yahoo и hotmail/outlook.com этого не делают, поэтому необходимо создать 2 события (по одному с каждым RRULE). При необходимости использование свойства RELATED-TO может помочь отслеживать их отношения.

person Auberon Vacher    schedule 11.02.2013
comment
Спасибо! Мне придется попробовать поиграть и подтвердить это сегодня вечером, но вы определенно правы насчет устаревания RFC; Я пропустил эту часть. - person ecmanaut; 11.02.2013
comment
Однако похоже, что правило Нового года нуждается в корректировке; если 1 января приходится на субботу, событие должно появиться в пятницу, 31 декабря предыдущего года, если в воскресенье, то в понедельник, 2 января; никогда 3 января. Но я не осознал логику, по которой вы стреляете, поэтому я мог упустить какую-то тонкость. - person ecmanaut; 11.02.2013
comment
на новогодние дни (США) нужно 2 RRULE, подробнее смотрите ответ выше - person Auberon Vacher; 11.02.2013
comment
Я думаю, что они всегда таковы, поскольку мы хотим, чтобы средняя (не первая и не последняя) дата имела приоритет, когда она приходится на будний день. Я обновил ваш ответ некоторыми дополнениями в конце - если вы еще этого не видите, подождите немного, прежде чем снова отредактировать ответ, и конечный результат будет еще лучше (я связал RFC-совместимые примеры для обоих стандарты). Хм. Я думаю, что BYMONTHDAY=4,3,5;BYSETPOS=1, вероятно, тоже сработает. - person ecmanaut; 12.02.2013
comment
Нет, нужны два правила: 4,3,5 не работали ни для одного порядка BYMONTHDAY и BYDAY, что, насколько я помню, соответствует правилам приоритета, указанным в спецификации. - person ecmanaut; 12.02.2013

ПРИМЕЧАНИЕ. В следующем ответе показано, как это сделать с помощью устаревшего RFC! Оставляю для справки, вдруг кому понадобится. Смотрите правильный ответ, чтобы узнать больше полезных фактов!

Вы можете сделать это, добавив соответствующие ежегодные повторяющиеся правила смежной пятницы и соседнего понедельника, которые отображают только те годы, когда дата имеет соответствующий день недели:

BEGIN:VEVENT
DTSTAMP:20130210T211949Z
UID:[email protected]
DTSTART;VALUE=DATE:20121231
DTEND;VALUE=DATE:20121231
SUMMARY:New Year’s Day (moved from a Saturday)
RRULE:FREQ=YEARLY;BYMONTH=12;BYMONTHDAY=31
EXRULE:FREQ=YEARLY;BYMONTH=12;BYMONTHDAY=31;BYDAY=MO,TU,WE,TH,SA,SU
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20130210T211949Z
UID:[email protected]
DTSTART;VALUE=DATE:20130102
DTEND;VALUE=DATE:20130102
SUMMARY:New Year’s Day (moved from a Sunday)
RRULE:FREQ=YEARLY;BYMONTH=1;BYMONTHDAY=2
EXRULE:FREQ=YEARLY;BYMONTH=1;BYMONTHDAY=2;BYDAY=TU,WE,TH,FR,SA,SU
END:VEVENT

Вместе с исходным событием (вы можете аналогичным образом отфильтровать это для BYDAY=MO,TU,WE,TH,FR, если вы не хотите, чтобы фактический праздник отображался в вашей ленте), вы охватываете все годы, не получая ложных срабатываний за годы, когда не было необходимости перемещать время. выходной в будний день:

BEGIN:VEVENT
DTSTAMP:20130210T211949Z
UID:[email protected]
DTSTART;VALUE=DATE:20130101
DTEND;VALUE=DATE:20130101
SUMMARY:New Year’s Day
RRULE:FREQ=YEARLY;BYMONTH=1;BYMONTHDAY=1
END:VEVENT

Календарь Google с удовольствием использует и понимает мой пример фида iCalendar. Текущий iCal (и устройства iOS, синхронизированные с календарем Google, который импортировал этот канал), к сожалению, содержит небольшие ошибки (зарегистрировано как  ошибка 13188350 [ссылка, вероятно, работает только для репортера]), и не удается применить указанные фильтры дней недели.

Но, надеюсь, это тоже скоро исправят.

person Community    schedule 11.02.2013