Даты хранить в UTC, в настройках запоминать текущий часовой пояс пользователя и ко применять его ко всем датам (либ всяких умных уже хватает, ищи)
Про рекуррентные - т.к. обычно у юзера таких дат не так много - например можно рассчитать одну ближайшую дату на момент создания.
На фоне у тебя будет работать job, который будет раз в минуту просчитывать для всех пользователей ,у которых есть рекуррентные события - не изменилось ли что-то(не прошёл ли ближайший день, к слову). Когда пользователь открывает календарь - ты можешь "на лету" прогнозировать отталкиваясь от того, что рекуррентное событие создано для него и отталкиваясь от времени/даты - учитывая просматриваемые даты/месяцы - скалькулировать даты и вывести грубо говоря. Там и подкешировать на время можно, чтобы не делать это каждую минуту при обновлении страницы/календаря.
если какое-то событие пользователь хочет поменять - заносишь в базу ссылку на рекуррент, и изменения. учитываешь это всё при построении модели "на лету".
"сразу создать в базе" так себе идея - создаст он "раз в час на протяжении 10 лет" - долго твоя база пустой не проживёт, да и чтобы что не очень понятно.
Конкретные экшены по точечным событиям - в базу. Вывод на экран - рантайм. Я бы так делал