@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<?php
2
3$table = new PhabricatorCalendarEvent();
4$conn = $table->establishConnection('w');
5$table_name = 'calendar_event';
6
7// Long ago, "All Day" events were stored with a start and end date set to
8// the earliest possible start and end seconds for the corresponding days. We
9// then moved to store all day events with their "date" epochs as UTC, separate
10// from individual event times. Both systems were later replaced with use of
11// CalendarDateTime.
12$zone_min = new DateTimeZone('Pacific/Midway');
13$zone_max = new DateTimeZone('Pacific/Kiritimati');
14$zone_utc = new DateTimeZone('UTC');
15
16foreach (new LiskRawMigrationIterator($conn, $table_name) as $row) {
17 $parameters = phutil_json_decode($row['parameters']);
18 if (isset($parameters['startDateTime'])) {
19 // This event has already been migrated.
20 continue;
21 }
22
23 $is_all_day = $row['isAllDay'];
24
25 if (empty($row['allDayDateFrom'])) {
26 // No "allDayDateFrom" means this is an old event which was never migrated
27 // by the earlier "20160715.event.03.allday.php" migration. The dateFrom
28 // and dateTo will be minimum and maximum earthly seconds for the event. We
29 // convert them to UTC if they were in extreme timezones.
30 $epoch_min = $row['dateFrom'];
31 $epoch_max = $row['dateTo'];
32
33 if ($is_all_day) {
34 $date_min = new DateTime('@'.$epoch_min);
35 $date_max = new DateTime('@'.$epoch_max);
36
37 $date_min->setTimeZone($zone_min);
38 $date_min->modify('+2 days');
39 $date_max->setTimeZone($zone_max);
40 $date_max->modify('-2 days');
41
42 $string_min = $date_min->format('Y-m-d');
43 $string_max = $date_max->format('Y-m-d 23:59:00');
44
45 $utc_min = id(new DateTime($string_min, $zone_utc))->format('U');
46 $utc_max = id(new DateTime($string_max, $zone_utc))->format('U');
47 } else {
48 $utc_min = $epoch_min;
49 $utc_max = $epoch_max;
50 }
51 } else {
52 // This is an event which was migrated already. We can pick the correct
53 // epoch timestamps based on the "isAllDay" flag.
54 if ($is_all_day) {
55 $utc_min = $row['allDayDateFrom'];
56 $utc_max = $row['allDayDateTo'];
57 } else {
58 $utc_min = $row['dateFrom'];
59 $utc_max = $row['dateTo'];
60 }
61 }
62
63 $utc_until = $row['recurrenceEndDate'];
64
65 $start_datetime = PhutilCalendarAbsoluteDateTime::newFromEpoch($utc_min);
66 if ($is_all_day) {
67 $start_datetime->setIsAllDay(true);
68 }
69
70 $end_datetime = PhutilCalendarAbsoluteDateTime::newFromEpoch($utc_max);
71 if ($is_all_day) {
72 $end_datetime->setIsAllDay(true);
73 }
74
75 if ($utc_until) {
76 $until_datetime = PhutilCalendarAbsoluteDateTime::newFromEpoch($utc_until);
77 } else {
78 $until_datetime = null;
79 }
80
81 $parameters['startDateTime'] = $start_datetime->toDictionary();
82 $parameters['endDateTime'] = $end_datetime->toDictionary();
83 if ($until_datetime) {
84 $parameters['untilDateTime'] = $until_datetime->toDictionary();
85 }
86
87 queryfx(
88 $conn,
89 'UPDATE %T SET parameters = %s WHERE id = %d',
90 $table_name,
91 phutil_json_encode($parameters),
92 $row['id']);
93}
94
95// Generate UTC epochs for all events. We can't readily do this one at a
96// time because instance UTC epochs rely on having the parent event.
97$viewer = PhabricatorUser::getOmnipotentUser();
98
99$all_events = id(new PhabricatorCalendarEventQuery())
100 ->setViewer($viewer)
101 ->execute();
102foreach ($all_events as $event) {
103 if ($event->getUTCInitialEpoch()) {
104 // Already migrated.
105 continue;
106 }
107
108 try {
109 $event->updateUTCEpochs();
110 } catch (Exception $ex) {
111 continue;
112 }
113
114 queryfx(
115 $conn,
116 'UPDATE %T SET
117 utcInitialEpoch = %d,
118 utcUntilEpoch = %nd,
119 utcInstanceEpoch = %nd WHERE id = %d',
120 $table_name,
121 $event->getUTCInitialEpoch(),
122 $event->getUTCUntilEpoch(),
123 $event->getUTCInstanceEpoch(),
124 $event->getID());
125}