Skip to content

Commit

Permalink
Don't erase event timezones (#653)
Browse files Browse the repository at this point in the history
* Add docs

* Add datetimes_to_icaltime testing framework

* Rewrite datetimes_to_icaltime; add associated tests

* Preserve original timezone of events

* Make TimeManager testable

* Clean up test code

* Add ICalTime->DateTime converters in event timezones

* Add MVP timezone label to editor

* WIP: load, display events in event timezone

* Fix errors in merge

* Fix compilation error

* Add more tests for icalcomponent_get_datetimes

* Display events in their time zone in editor

* Convert end time zone to start if necessary

Currently, we only support one time zone in the editor.
This is necessary for that assumption, since it's possible
to create events with different start/end zones.

* Fix leftover is_date reset

* Fix docs typo

* Fix empty timezone for new event

Co-authored-by: Michael McClurg <[email protected]>
Co-authored-by: Cassidy James Blaede <[email protected]>
Co-authored-by: Marco Betschart <[email protected]>
  • Loading branch information
4 people authored Sep 17, 2021
1 parent be2353f commit ee704e7
Show file tree
Hide file tree
Showing 6 changed files with 291 additions and 73 deletions.
16 changes: 16 additions & 0 deletions core/Services/Calendar/TimeManager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,20 @@ public class Calendar.TimeManager : Object {

return instance;
}

// Sets up a new TimeManager for testing, which uses settable values.
// This overwrites the default instance, so once this is called
// get_default can be used as usual to return the test object.
public static unowned TimeManager setup_test (ICal.Timezone system_timezone) {
if (instance != null) {
warning ("Resetting default TimeManager to new testing instance");
}

instance = new TimeManager.for_testing (system_timezone);
return instance;
}

private TimeManager.for_testing (ICal.Timezone system_timezone) {
this.system_timezone = system_timezone;
}
}
68 changes: 43 additions & 25 deletions core/Services/Calendar/Util/DateTime.vala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2020 elementary, Inc. (https://elementary.io)
* Copyright 2011-2021 elementary, Inc. (https://elementary.io)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
Expand Down Expand Up @@ -43,49 +43,67 @@ namespace Calendar.Util {
}

/**
* Converts two datetimes to one TimeType. The first contains the date,
* its time settings are ignored. The second one contains the time itself.
* Converts two DateTimes representing a date and a time to one TimeType.
*
* The first contains the date; its time settings are ignored. The second
* one contains the time itself; its date settings are ignored. If the time
* is `null`, the resulting TimeType is of `DATE` type; if it is given, the
* TimeType is of `DATE-TIME` type.
*
* This also accepts an optional `timezone` argument. If it is given a
* timezone, the resulting TimeType will be relative to the given timezone.
* If it is `null`, the resulting TimeType will be "floating" with no
* timezone. If the argument is not given, it will default to the system
* timezone.
*/
public ICal.Time datetimes_to_icaltime (GLib.DateTime date, GLib.DateTime? time_local, string? timezone = null) {
public ICal.Time datetimes_to_icaltime (GLib.DateTime date, GLib.DateTime? time_local,
ICal.Timezone? timezone = Calendar.TimeManager.get_default ().system_timezone) {

#if E_CAL_2_0
var result = new ICal.Time.from_day_of_year (date.get_day_of_year (), date.get_year ());
#else
var result = ICal.Time.from_day_of_year (date.get_day_of_year (), date.get_year ());
#endif
if (time_local != null) {
if (timezone != null) {

// Check if it's a date. If so, set is_date to true and fix the time to be sure.
// If it's not a date, first thing set is_date to false.
// Then, set the timezone.
// Then, set the time.
if (time_local == null) {
// Date type: ensure that everything corresponds to a date
#if E_CAL_2_0
result.set_timezone (ICal.Timezone.get_builtin_timezone (timezone));
result.set_is_date (true);
result.set_time (0, 0, 0);
#else
result.zone = ICal.Timezone.get_builtin_timezone (timezone);
result._is_date = 1;
result.hour = 0;
result.minute = 0;
result.second = 0;
#endif
} else {
unowned var time_manager = Calendar.TimeManager.get_default ();
} else {
// Includes time
// Set is_date first (otherwise timezone won't change)
#if E_CAL_2_0
result.set_timezone (time_manager.system_timezone);
result.set_is_date (false);
#else
result.zone = event_store.system_timezone;
result._is_date = 0;
#endif
}

// Set timezone for the time to be relative to
// (doesn't affect DATE-type times)
#if E_CAL_2_0
result.set_timezone (timezone);
#else
result.zone = timezone;
#endif

// Set the time with the updated time zone
#if E_CAL_2_0
result.set_is_date (false);
result.set_time (time_local.get_hour (), time_local.get_minute (), time_local.get_second ());
#else
result._is_date = 0;
result.hour = time_local.get_hour ();
result.minute = time_local.get_minute ();
result.second = time_local.get_second ();
#endif
} else {
#if E_CAL_2_0
result.set_is_date (true);
result.set_time (0, 0, 0);
#else
result._is_date = 1;
result.hour = 0;
result.minute = 0;
result.second = 0;
#endif
}

Expand Down
32 changes: 27 additions & 5 deletions core/Services/Calendar/Util/ICalComponent.vala
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,32 @@ namespace Calendar.Util {
//--- ICal.Component Helpers ---//

/** Gets a pair of {@link GLib.DateTime} objects representing the start and
* end of the given component.
* end of the given component, represented in the system time zone.
*/
public void icalcomponent_get_local_datetimes (ICal.Component component, out GLib.DateTime start_date, out GLib.DateTime end_date) {
icalcomponent_get_datetimes (component, out start_date, out end_date);

if (!Calendar.Util.datetime_is_all_day (start_date, end_date)) {
// Don't convert timezone for date with only day info, which is considered floating
start_date = start_date.to_local ();
end_date = end_date.to_local ();
}
}

/** Gets a pair of {@link GLib.DateTime} objects representing the start and
* end of the given component, represented in the time zone of @component.
*/
public void icalcomponent_get_datetimes (ICal.Component component, out GLib.DateTime start_date, out GLib.DateTime end_date) {
ICal.Time dt_start = component.get_dtstart ();
ICal.Time dt_end = component.get_dtend ();
start_date = Calendar.Util.icaltime_to_datetime (dt_start);

start_date = Calendar.Util.icaltime_to_datetime (dt_start).to_local ();

// Get end date, which can be specified in multiple ways
if (!dt_end.is_null_time ()) {
end_date = Calendar.Util.icaltime_to_datetime (dt_end).to_local ();
end_date = Calendar.Util.icaltime_to_datetime (dt_end);
} else if (!component.get_duration ().is_null_duration ()) {
end_date = Calendar.Util.icaltime_to_datetime (dt_start.add (component.get_duration ())).to_local ();
dt_end = dt_start.add (component.get_duration ());
end_date = Calendar.Util.icaltime_to_datetime (dt_end);
} else if (dt_start.is_date ()) {
end_date = start_date.add_days (1); // Implicitly 1 day long
} else {
Expand Down Expand Up @@ -67,6 +81,14 @@ namespace Calendar.Util {
}
}

public void icalcomponent_get_datetimes_for_display (ICal.Component component, out GLib.DateTime start_date, out GLib.DateTime end_date) {
icalcomponent_get_datetimes (component, out start_date, out end_date);

if (datetime_is_all_day (start_date, end_date)) {
end_date = end_date.add_days (-1);
}
}

/** Returns whether the given icalcomponent overlaps with the time range.
*
* This is true if the icalcomponent either starts or ends within the range, even
Expand Down
2 changes: 2 additions & 0 deletions core/Services/Calendar/Util/ICalTime.vala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ namespace Calendar.Util {

/**
* Gets the timezone of the given TimeType as a GLib.TimeZone.
*
* For floating times, returns the local timezone.
* Dates (with no time component) are considered floating.
*/
public GLib.TimeZone icaltime_get_timezone (ICal.Time date) {
// Special case: dates are floating, so return local time zone
Expand Down
Loading

0 comments on commit ee704e7

Please sign in to comment.