@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Schedule monthly events on the 29th, 30th or 31st relative to the end of the month

Summary:
Ref T11326. If you scheudle a monthly event on the 31st, the default behavior of RRULE means that it only occurs in months with 31 days.

This is actually how Google Calendar and Calendar.app both work: if you schedule a monthly event on the 31st, you get about six events per year.

This seems real confusing and bad to me?

Instead, if the user schedules a monthly event on the 29th, 30th or 31st, pretend they scheduled it on the "last day of the month" or "second-to-last day of the month" or similar, so they always get 12 events per year.

This could be slightly confusing too, but seems way less weird than not getting an event every month.

Test Plan: Scheduled events on the 31st of October, saw them occur in November too after the patch.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T11326

Differential Revision: https://secure.phabricator.com/D16775

+27
+27
src/applications/calendar/xaction/PhabricatorCalendarEventFrequencyTransaction.php
··· 19 19 $rrule = id(new PhutilCalendarRecurrenceRule()) 20 20 ->setFrequency($value); 21 21 22 + // If the user creates a monthly event on the 29th, 30th or 31st of a 23 + // month, it means "the 30th of every month" as far as the RRULE is 24 + // concerned. Such an event will not occur on months with fewer days. 25 + 26 + // This is surprising, and proably not what the user wants. Instead, 27 + // schedule these events relative to the end of the month: on the "-1st", 28 + // "-2nd" or "-3rd" day of the month. For example, a monthly event on 29 + // the 31st of a 31-day month translates to "every month, on the last 30 + // day of the month". 31 + if ($value == PhutilCalendarRecurrenceRule::FREQUENCY_MONTHLY) { 32 + $start_datetime = $object->newStartDateTime(); 33 + 34 + $y = $start_datetime->getYear(); 35 + $m = $start_datetime->getMonth(); 36 + $d = $start_datetime->getDay(); 37 + if ($d >= 29) { 38 + $year_map = PhutilCalendarRecurrenceRule::getYearMap( 39 + $y, 40 + PhutilCalendarRecurrenceRule::WEEKDAY_MONDAY); 41 + 42 + $month_days = $year_map['monthDays'][$m]; 43 + $schedule_on = -(($month_days + 1) - $d); 44 + 45 + $rrule->setByMonthDay(array($schedule_on)); 46 + } 47 + } 48 + 22 49 $object->setRecurrenceRule($rrule); 23 50 } 24 51