Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15380319
D16652.id40144.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
5 KB
Referenced Files
None
Subscribers
None
D16652.id40144.diff
View Options
diff --git a/resources/sql/autopatches/20161003.cal.01.utcepoch.sql b/resources/sql/autopatches/20161003.cal.01.utcepoch.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20161003.cal.01.utcepoch.sql
@@ -0,0 +1,8 @@
+ALTER TABLE {$NAMESPACE}_calendar.calendar_event
+ ADD utcInitialEpoch INT UNSIGNED NOT NULL;
+
+ALTER TABLE {$NAMESPACE}_calendar.calendar_event
+ ADD utcUntilEpoch INT UNSIGNED;
+
+ALTER TABLE {$NAMESPACE}_calendar.calendar_event
+ ADD utcInstanceEpoch INT UNSIGNED;
diff --git a/src/applications/calendar/storage/PhabricatorCalendarEvent.php b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
--- a/src/applications/calendar/storage/PhabricatorCalendarEvent.php
+++ b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
@@ -41,11 +41,16 @@
protected $spacePHID;
+ protected $utcInitialEpoch;
+ protected $utcUntilEpoch;
+ protected $utcInstanceEpoch;
+
private $parentEvent = self::ATTACHABLE;
private $invitees = self::ATTACHABLE;
private $viewerDateFrom;
private $viewerDateTo;
+ private $viewerTimezone;
// Frequency Constants
const FREQUENCY_DAILY = 'daily';
@@ -298,6 +303,8 @@
$zone);
}
+ $this->viewerTimezone = $viewer->getTimezoneIdentifier();
+
return $this;
}
@@ -323,11 +330,62 @@
return $dst->format('U');
}
+ public function updateUTCEpochs() {
+ // The "intitial" epoch is the start time of the event, in UTC.
+ $start_date = $this->newStartDateTime()
+ ->setViewerTimezone('UTC');
+ $start_epoch = $start_date->getEpoch();
+ $this->setUTCInitialEpoch($start_epoch);
+
+ // The "until" epoch is the last UTC epoch on which any instance of this
+ // event occurs. For infinitely recurring events, it is `null`.
+
+ if (!$this->getIsRecurring()) {
+ $end_date = $this->newEndDateTime()
+ ->setViewerTimezone('UTC');
+ $until_epoch = $end_date->getEpoch();
+ } else {
+ $until_epoch = null;
+ $until_date = $this->newUntilDateTime()
+ ->setViewerTimezone('UTC');
+ if ($until_date) {
+ $duration = $this->newDuration();
+ $until_epoch = id(new PhutilCalendarRelativeDateTime())
+ ->setOrigin($until_date)
+ ->setDuration($duration)
+ ->getEpoch();
+ }
+ }
+ $this->setUTCUntilEpoch($until_epoch);
+
+ // The "instance" epoch is a property of instances of recurring events.
+ // It's the original UTC epoch on which the instance started. Usually that
+ // is the same as the start date, but they may be different if the instance
+ // has been edited.
+
+ // The ICS format uses this value (original start time) to identify event
+ // instances, and must do so because it allows additional arbitrary
+ // instances to be added (with "RDATE").
+
+ $instance_epoch = null;
+ $instance_date = $this->newInstanceDateTime();
+ if ($instance_date) {
+ $instance_epoch = $instance_date
+ ->setViewerTimezone('UTC')
+ ->getEpoch();
+ }
+ $this->setUTCInstanceEpoch($instance_epoch);
+
+ return $this;
+ }
+
public function save() {
if (!$this->mailKey) {
$this->mailKey = Filesystem::readRandomCharacters(20);
}
+ $this->updateUTCEpochs();
+
return parent::save();
}
@@ -363,6 +421,9 @@
'instanceOfEventPHID' => 'phid?',
'sequenceIndex' => 'uint32?',
'isStub' => 'bool',
+ 'utcInitialEpoch' => 'epoch',
+ 'utcUntilEpoch' => 'epoch?',
+ 'utcInstanceEpoch' => 'epoch?',
),
self::CONFIG_KEY_SCHEMA => array(
'key_date' => array(
@@ -372,6 +433,13 @@
'columns' => array('instanceOfEventPHID', 'sequenceIndex'),
'unique' => true,
),
+ 'key_epoch' => array(
+ 'columns' => array('utcInitialEpoch', 'utcUntilEpoch'),
+ ),
+ 'key_rdate' => array(
+ 'columns' => array('instanceOfEventPHID', 'utcInstanceEpoch'),
+ 'unique' => true,
+ ),
),
self::CONFIG_SERIALIZATION => array(
'recurrenceFrequency' => self::SERIALIZATION_JSON,
@@ -641,11 +709,8 @@
$modified = $this->getDateModified();
$modified = PhutilCalendarAbsoluteDateTime::newFromEpoch($modified);
- $date_start = $this->getDateFrom();
- $date_start = PhutilCalendarAbsoluteDateTime::newFromEpoch($date_start);
-
- $date_end = $this->getDateTo();
- $date_end = PhutilCalendarAbsoluteDateTime::newFromEpoch($date_end);
+ $date_start = $this->newStartDateTime();
+ $date_end = $this->newEndDateTime();
if ($this->getIsAllDay()) {
$date_start->setIsAllDay(true);
@@ -719,6 +784,57 @@
return $node;
}
+ public function newStartDateTime() {
+ $epoch = $this->getDateFrom();
+ return $this->newDateTimeFromEpoch($epoch);
+ }
+
+ public function newEndDateTime() {
+ $epoch = $this->getDateTo();
+ return $this->newDateTimeFromEpoch($epoch);
+ }
+
+ public function newUntilDateTime() {
+ $epoch = $this->getRecurrenceEndDate();
+ if (!$epoch) {
+ return null;
+ }
+ return $this->newDateTimeFromEpoch($epoch);
+ }
+
+ public function newDuration() {
+ return id(new PhutilCalendarDuration())
+ ->setSeconds($this->getDuration());
+ }
+
+ public function newInstanceDateTime() {
+ if (!$this->getIsRecurring()) {
+ return null;
+ }
+
+ $epochs = $this->getParent()->getSequenceIndexEpochs(
+ new PhabricatorUser(),
+ $this->getSequenceIndex(),
+ $this->getDuration());
+
+ $epoch = $epochs['dateFrom'];
+ return $this->newDateTimeFromEpoch($epoch);
+ }
+
+ private function newDateTimeFromEpoch($epoch) {
+ $datetime = PhutilCalendarAbsoluteDateTime::newFromEpoch($epoch);
+
+ $viewer_timezone = $this->viewerTimezone;
+ if ($viewer_timezone) {
+ $datetime->setViewerTimezone($viewer_timezone);
+ }
+
+ if ($this->getIsAllDay()) {
+ $datetime->setIsAllDay(true);
+ }
+
+ return $datetime;
+ }
/* -( Markup Interface )--------------------------------------------------- */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Mar 15, 2:32 AM (1 w, 1 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7223582
Default Alt Text
D16652.id40144.diff (5 KB)
Attached To
Mode
D16652: Introduce Calendar "UTC Epoch" columns for query windowing
Attached
Detach File
Event Timeline
Log In to Comment