Merge lp:~laney/indicator-datetime/eds-3.16 into lp:indicator-datetime/15.10

Proposed by Iain Lane on 2015-07-20
Status: Merged
Approved by: Iain Lane on 2015-07-20
Approved revision: 414
Merged at revision: 418
Proposed branch: lp:~laney/indicator-datetime/eds-3.16
Merge into: lp:indicator-datetime/15.10
Diff against target: 597 lines (+355/-30)
9 files modified
CMakeLists.txt (+1/-1)
debian/changelog (+13/-0)
debian/control (+1/-1)
src/engine-eds.cpp (+69/-28)
tests/CMakeLists.txt (+2/-0)
tests/test-eds-ics-tzids-2.cpp (+88/-0)
tests/test-eds-ics-tzids-2.ics (+38/-0)
tests/test-eds-ics-tzids.cpp (+87/-0)
tests/test-eds-ics-tzids.ics (+56/-0)
To merge this branch: bzr merge lp:~laney/indicator-datetime/eds-3.16
Reviewer Review Type Date Requested Status
Iain Lane Approve on 2015-07-20
PS Jenkins bot continuous-integration Needs Fixing on 2015-07-20
Review via email: mp+265287@code.launchpad.net

Commit Message

Update for e-d-s 3.16

Description of the Change

To post a comment you must log in.
Iain Lane (laney) wrote :

Self approving since https://code.launchpad.net/~robert-ancell/indicator-datetime/libecal-3.16/+merge/260789 was approved and it's functionally the same.

Thanks robert_ancell. :)

review: Approve
415. By Iain Lane on 2015-07-22

Merge with 15.04 branch which is what got uploaded to the archive

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-08-19 04:03:38 +0000
3+++ CMakeLists.txt 2015-07-22 12:03:21 +0000
4@@ -36,7 +36,7 @@
5 glib-2.0>=2.36
6 gio-unix-2.0>=2.36
7 libical>=0.48
8- libecal-1.2>=3.5
9+ libecal-1.2>=3.16
10 libedataserver-1.2>=3.5
11 gstreamer-1.0>=1.2
12 libnotify>=0.7.6
13
14=== modified file 'debian/changelog'
15--- debian/changelog 2015-06-24 12:51:27 +0000
16+++ debian/changelog 2015-07-22 12:03:21 +0000
17@@ -1,3 +1,9 @@
18+indicator-datetime (13.10.0+15.10.20150710.1-0ubuntu1) wily; urgency=medium
19+
20+ * New rebuild forced.
21+
22+ -- CI Train Bot <ci-train-bot@canonical.com> Fri, 10 Jul 2015 20:35:47 +0000
23+
24 indicator-datetime (13.10.0+15.10.20150624-0ubuntu1) wily; urgency=medium
25
26 [ Charles Kerr ]
27@@ -21,6 +27,13 @@
28
29 -- CI Train Bot <ci-train-bot@canonical.com> Fri, 15 May 2015 16:41:41 +0000
30
31+indicator-datetime (13.10.0+15.04.20150618-0ubuntu1) vivid; urgency=medium
32+
33+ [ Charles Kerr ]
34+ * Fix invalid valarms in older clock-app alarms. (LP: #1465806)
35+
36+ -- CI Train Bot <ci-train-bot@canonical.com> Thu, 18 Jun 2015 19:25:41 +0000
37+
38 indicator-datetime (13.10.0+15.04.20150406-0ubuntu1) vivid; urgency=medium
39
40 [ Charles Kerr ]
41
42=== modified file 'debian/control'
43--- debian/control 2015-04-06 14:25:59 +0000
44+++ debian/control 2015-07-22 12:03:21 +0000
45@@ -9,7 +9,7 @@
46 libglib2.0-dev (>= 2.35.4),
47 libnotify-dev (>= 0.7.6),
48 libgstreamer1.0-dev,
49- libecal1.2-dev (>= 3.5),
50+ libecal1.2-dev (>= 3.16),
51 libical-dev (>= 1.0),
52 libedataserver1.2-dev (>= 3.5),
53 liburl-dispatcher1-dev,
54
55=== modified file 'src/engine-eds.cpp'
56--- src/engine-eds.cpp 2015-06-18 04:53:52 +0000
57+++ src/engine-eds.cpp 2015-07-22 12:03:21 +0000
58@@ -47,16 +47,21 @@
59 {
60 public:
61
62- Impl():
63- m_cancellable(g_cancellable_new())
64+ Impl()
65 {
66- e_source_registry_new(m_cancellable, on_source_registry_ready, this);
67+ auto cancellable_deleter = [](GCancellable * c) {
68+ g_cancellable_cancel(c);
69+ g_clear_object(&c);
70+ };
71+
72+ m_cancellable = std::shared_ptr<GCancellable>(g_cancellable_new(), cancellable_deleter);
73+
74+ e_source_registry_new(m_cancellable.get(), on_source_registry_ready, this);
75 }
76
77 ~Impl()
78 {
79- g_cancellable_cancel(m_cancellable);
80- g_clear_object(&m_cancellable);
81+ m_cancellable.reset();
82
83 while(!m_sources.empty())
84 remove_source(*m_sources.begin());
85@@ -131,9 +136,9 @@
86 e_cal_client_get_object_list_as_comps(
87 client,
88 sexp,
89- m_cancellable,
90+ m_cancellable.get(),
91 on_alarm_component_list_ready,
92- new ClientSubtask(main_task, client, color));
93+ new ClientSubtask(main_task, client, m_cancellable, color));
94 g_clear_pointer(&sexp, g_free);
95
96 // ask EDS about events that occur in this window...
97@@ -142,9 +147,9 @@
98 e_cal_client_get_object_list_as_comps(
99 client,
100 sexp,
101- m_cancellable,
102+ m_cancellable.get(),
103 on_event_component_list_ready,
104- new ClientSubtask(main_task, client, color));
105+ new ClientSubtask(main_task, client, m_cancellable, color));
106 g_clear_pointer(&sexp, g_free);
107
108 g_clear_pointer(&sexp_fmt, g_free);
109@@ -160,7 +165,7 @@
110 e_cal_client_get_object(kv.second,
111 appointment.uid.c_str(),
112 nullptr,
113- m_cancellable,
114+ m_cancellable.get(),
115 on_object_ready_for_disable,
116 this);
117 }
118@@ -271,7 +276,8 @@
119 g_debug("%s connecting a client to source %s", G_STRFUNC, source_uid);
120 e_cal_client_connect(source,
121 source_type,
122- self->m_cancellable,
123+ -1,
124+ self->m_cancellable.get(),
125 on_client_connected,
126 gself);
127 }
128@@ -306,7 +312,7 @@
129 // now create a view for it so that we can listen for changes
130 e_cal_client_get_view (ecc,
131 "#t", // match all
132- self->m_cancellable,
133+ self->m_cancellable.get(),
134 on_client_view_ready,
135 self);
136
137@@ -429,7 +435,7 @@
138 e_cal_client_get_object_list_as_comps(
139 client,
140 sexp,
141- m_cancellable,
142+ m_cancellable.get(),
143 ensure_client_alarms_have_triggers_async_cb,
144 this);
145
146@@ -510,7 +516,7 @@
147 e_cal_client_modify_objects(client,
148 modify_slist,
149 E_CAL_OBJ_MOD_ALL,
150- m_cancellable,
151+ m_cancellable.get(),
152 ensure_canonical_alarms_have_triggers_async_cb,
153 this);
154
155@@ -580,13 +586,16 @@
156 {
157 std::shared_ptr<Task> task;
158 ECalClient* client;
159+ std::shared_ptr<GCancellable> cancellable;
160 std::string color;
161
162 ClientSubtask(const std::shared_ptr<Task>& task_in,
163 ECalClient* client_in,
164+ const std::shared_ptr<GCancellable>& cancellable_in,
165 const char* color_in):
166 task(task_in),
167- client(client_in)
168+ client(client_in),
169+ cancellable(cancellable_in)
170 {
171 if (color_in)
172 color = color_in;
173@@ -720,15 +729,44 @@
174 }
175
176 static DateTime
177- datetime_from_component_date_time(const ECalComponentDateTime & in,
178- GTimeZone * default_timezone)
179+ datetime_from_component_date_time(ECalClient * client,
180+ std::shared_ptr<GCancellable> & cancellable,
181+ const ECalComponentDateTime & in,
182+ GTimeZone * default_timezone)
183 {
184 DateTime out;
185-
186 g_return_val_if_fail(in.value != nullptr, out);
187
188- auto gtz = in.tzid == nullptr ? g_time_zone_ref(default_timezone)
189- : g_time_zone_new(in.tzid);
190+ GTimeZone * gtz {};
191+ if (in.tzid != nullptr)
192+ {
193+ auto itz = icaltimezone_get_builtin_timezone_from_tzid(in.tzid); // usually works
194+
195+ if (itz == nullptr) // fallback
196+ itz = icaltimezone_get_builtin_timezone(in.tzid);
197+
198+ if (itz == nullptr) // ok we have a strange tzid... ask EDS to look it up in VTIMEZONES
199+ e_cal_client_get_timezone_sync(client, in.tzid, &itz, cancellable.get(), nullptr);
200+
201+ const char * tzid;
202+ if (itz != nullptr)
203+ {
204+ tzid = icaltimezone_get_location(itz);
205+ }
206+ else
207+ {
208+ g_warning("Unrecognized TZID: '%s'", in.tzid);
209+ tzid = nullptr;
210+ }
211+
212+ gtz = g_time_zone_new(tzid);
213+ g_debug("%s eccdt.tzid -> offset is %d", G_STRLOC, in.tzid, (int)g_time_zone_get_offset(gtz,0));
214+ }
215+ else
216+ {
217+ gtz = g_time_zone_ref(default_timezone);
218+ }
219+
220 out = DateTime(gtz,
221 in.value->year,
222 in.value->month,
223@@ -773,7 +811,10 @@
224 }
225
226 static Appointment
227- get_appointment(ECalComponent * component, GTimeZone * gtz)
228+ get_appointment(ECalClient * client,
229+ std::shared_ptr<GCancellable> & cancellable,
230+ ECalComponent * component,
231+ GTimeZone * gtz)
232 {
233 Appointment baseline;
234
235@@ -792,13 +833,13 @@
236 // get appointment.begin
237 ECalComponentDateTime eccdt_tmp {};
238 e_cal_component_get_dtstart(component, &eccdt_tmp);
239- baseline.begin = datetime_from_component_date_time(eccdt_tmp, gtz);
240+ baseline.begin = datetime_from_component_date_time(client, cancellable, eccdt_tmp, gtz);
241 e_cal_component_free_datetime(&eccdt_tmp);
242
243 // get appointment.end
244 e_cal_component_get_dtend(component, &eccdt_tmp);
245 baseline.end = eccdt_tmp.value != nullptr
246- ? datetime_from_component_date_time(eccdt_tmp, gtz)
247+ ? datetime_from_component_date_time(client, cancellable, eccdt_tmp, gtz)
248 : baseline.begin;
249 e_cal_component_free_datetime(&eccdt_tmp);
250
251@@ -839,7 +880,7 @@
252 ClientSubtask * subtask,
253 GTimeZone * gtz)
254 {
255- // events with alarms are covered by add_alarm_to_subtask(),
256+ // events with alarms are covered by add_alarms_to_subtask(),
257 // so skip them here
258 auto auids = e_cal_component_get_alarm_uids(component);
259 const bool has_alarms = auids != nullptr;
260@@ -850,7 +891,7 @@
261 // add it. simple, eh?
262 if (is_component_interesting(component))
263 {
264- Appointment appointment = get_appointment(component, gtz);
265+ Appointment appointment = get_appointment(subtask->client, subtask->cancellable, component, gtz);
266 appointment.color = subtask->color;
267 subtask->task->appointments.push_back(appointment);
268 }
269@@ -866,7 +907,7 @@
270 if (!is_component_interesting(component))
271 return;
272
273- Appointment baseline = get_appointment(component, gtz);
274+ Appointment baseline = get_appointment(subtask->client, subtask->cancellable, component, gtz);
275 baseline.color = subtask->color;
276
277 /**
278@@ -958,7 +999,7 @@
279 e_cal_client_modify_object(E_CAL_CLIENT(client),
280 e_cal_component_get_icalcomponent(ecc),
281 E_CAL_OBJ_MOD_THIS,
282- static_cast<Impl*>(gself)->m_cancellable,
283+ static_cast<Impl*>(gself)->m_cancellable.get(),
284 on_disable_done,
285 nullptr);
286
287@@ -990,7 +1031,7 @@
288 std::set<ESource*> m_sources;
289 std::map<ESource*,ECalClient*> m_clients;
290 std::map<ESource*,ECalClientView*> m_views;
291- GCancellable* m_cancellable {};
292+ std::shared_ptr<GCancellable> m_cancellable;
293 ESourceRegistry* m_source_registry {};
294 guint m_rebuild_tag {};
295 time_t m_rebuild_deadline {};
296
297=== modified file 'tests/CMakeLists.txt'
298--- tests/CMakeLists.txt 2015-06-23 13:00:28 +0000
299+++ tests/CMakeLists.txt 2015-07-22 12:03:21 +0000
300@@ -88,6 +88,8 @@
301 add_eds_ics_test_by_name(test-eds-ics-nonrepeating-events)
302 add_eds_ics_test_by_name(test-eds-ics-repeating-valarms)
303 add_eds_ics_test_by_name(test-eds-ics-missing-trigger)
304+add_eds_ics_test_by_name(test-eds-ics-tzids)
305+add_eds_ics_test_by_name(test-eds-ics-tzids-2)
306
307
308 # disabling the timezone unit tests because they require
309
310=== added file 'tests/test-eds-ics-tzids-2.cpp'
311--- tests/test-eds-ics-tzids-2.cpp 1970-01-01 00:00:00 +0000
312+++ tests/test-eds-ics-tzids-2.cpp 2015-07-22 12:03:21 +0000
313@@ -0,0 +1,88 @@
314+/*
315+ * Copyright 2015 Canonical Ltd.
316+ *
317+ * This program is free software: you can redistribute it and/or modify it
318+ * under the terms of the GNU General Public License version 3, as published
319+ * by the Free Software Foundation.
320+ *
321+ * This program is distributed in the hope that it will be useful, but
322+ * WITHOUT ANY WARRANTY; without even the implied warranties of
323+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
324+ * PURPOSE. See the GNU General Public License for more details.
325+ *
326+ * You should have received a copy of the GNU General Public License along
327+ * with this program. If not, see <http://www.gnu.org/licenses/>.
328+ *
329+ * Authors:
330+ * Charles Kerr <charles.kerr@canonical.com>
331+ */
332+
333+#include <algorithm>
334+
335+#include <datetime/alarm-queue-simple.h>
336+#include <datetime/clock-mock.h>
337+#include <datetime/engine-eds.h>
338+#include <datetime/planner-range.h>
339+
340+#include <gtest/gtest.h>
341+
342+#include "glib-fixture.h"
343+#include "print-to.h"
344+#include "timezone-mock.h"
345+#include "wakeup-timer-mock.h"
346+
347+using namespace unity::indicator::datetime;
348+using VAlarmFixture = GlibFixture;
349+
350+/***
351+****
352+***/
353+
354+TEST_F(VAlarmFixture, MultipleAppointments)
355+{
356+ // start the EDS engine
357+ auto engine = std::make_shared<EdsEngine>();
358+
359+ // we need a consistent timezone for the planner and our local DateTimes
360+ constexpr char const * zone_str {"America/Los_Angeles"};
361+ auto tz = std::make_shared<MockTimezone>(zone_str);
362+ auto gtz = g_time_zone_new(zone_str);
363+
364+ // make a planner that looks at the first half of 2015 in EDS
365+ auto planner = std::make_shared<SimpleRangePlanner>(engine, tz);
366+ const DateTime range_begin {gtz, 2006,1, 1, 0, 0, 0.0};
367+ const DateTime range_end {gtz, 2015,12,31,23,59,59.5};
368+ planner->range().set(std::make_pair(range_begin, range_end));
369+
370+ // give EDS a moment to load
371+ if (planner->appointments().get().empty()) {
372+ g_message("waiting a moment for EDS to load...");
373+ auto on_appointments_changed = [this](const std::vector<Appointment>& appointments){
374+ g_message("ah, they loaded");
375+ if (!appointments.empty())
376+ g_main_loop_quit(loop);
377+ };
378+ core::ScopedConnection conn(planner->appointments().changed().connect(on_appointments_changed));
379+ constexpr int max_wait_sec = 10;
380+ wait_msec(max_wait_sec * G_TIME_SPAN_MILLISECOND);
381+ }
382+
383+ // what we expect to get...
384+ std::array<Appointment,1> expected_appts;
385+ auto appt = &expected_appts[0];
386+ appt->uid = "109264742";
387+ appt->color = "#becedd";
388+ appt->summary = "National Incubator Initiative for Clean Energy (NIICE) FOA: Pre-Concept Paper Informational Webinar";
389+ appt->begin = DateTime{gtz,2014,1,21,11,0,0};
390+ appt->end = DateTime{gtz,2014,1,21,13,0,0};
391+ appt->alarms = std::vector<Alarm>{ Alarm({"Reminder", "", DateTime(gtz,2014,1,21,10,45,0)}) };
392+
393+ // compare it to what we actually loaded...
394+ const auto appts = planner->appointments().get();
395+ EXPECT_EQ(expected_appts.size(), appts.size());
396+ for (size_t i=0, n=std::min(appts.size(),expected_appts.size()); i<n; i++)
397+ EXPECT_EQ(expected_appts[i], appts[i]);
398+
399+ // cleanup
400+ g_time_zone_unref(gtz);
401+}
402
403=== added file 'tests/test-eds-ics-tzids-2.ics'
404--- tests/test-eds-ics-tzids-2.ics 1970-01-01 00:00:00 +0000
405+++ tests/test-eds-ics-tzids-2.ics 2015-07-22 12:03:21 +0000
406@@ -0,0 +1,38 @@
407+BEGIN:VCALENDAR
408+CALSCALE:GREGORIAN
409+PRODID:-//Ximian//NONSGML Evolution Calendar//EN
410+VERSION:2.0
411+X-EVOLUTION-DATA-REVISION:2015-07-09T19:41:50.123217Z(3)
412+BEGIN:VTIMEZONE
413+TZID:Pacific Time (US & Canada)
414+BEGIN:STANDARD
415+DTSTART:20061105T020000
416+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
417+TZOFFSETFROM:-0700
418+TZOFFSETTO:-0800
419+END:STANDARD
420+BEGIN:DAYLIGHT
421+DTSTART:20070311T020000
422+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
423+TZOFFSETFROM:-0800
424+TZOFFSETTO:-0700
425+TZNAME:Daylight Savings Time
426+END:DAYLIGHT
427+END:VTIMEZONE
428+BEGIN:VEVENT
429+DTSTART;TZID=Pacific Time (US & Canada):20140121T110000
430+DTEND;TZID=Pacific Time (US & Canada):20140121T130000
431+UID:109264742
432+DTSTAMP:20140120T000718Z
433+DESCRIPTION: Event description
434+SUMMARY;ENCODING=QUOTED-PRINTABLE:National Incubator Initiative for Clean
435+ Energy (NIICE) FOA: Pre-Concept Paper Informational Webinar
436+CREATED:20140120T000741Z
437+LAST-MODIFIED:20140120T000741Z
438+BEGIN:VALARM
439+TRIGGER;VALUE=DURATION:-PT15M
440+ACTION:DISPLAY
441+DESCRIPTION:Reminder
442+END:VALARM
443+END:VEVENT
444+END:VCALENDAR
445
446=== added file 'tests/test-eds-ics-tzids.cpp'
447--- tests/test-eds-ics-tzids.cpp 1970-01-01 00:00:00 +0000
448+++ tests/test-eds-ics-tzids.cpp 2015-07-22 12:03:21 +0000
449@@ -0,0 +1,87 @@
450+/*
451+ * Copyright 2015 Canonical Ltd.
452+ *
453+ * This program is free software: you can redistribute it and/or modify it
454+ * under the terms of the GNU General Public License version 3, as published
455+ * by the Free Software Foundation.
456+ *
457+ * This program is distributed in the hope that it will be useful, but
458+ * WITHOUT ANY WARRANTY; without even the implied warranties of
459+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
460+ * PURPOSE. See the GNU General Public License for more details.
461+ *
462+ * You should have received a copy of the GNU General Public License along
463+ * with this program. If not, see <http://www.gnu.org/licenses/>.
464+ *
465+ * Authors:
466+ * Charles Kerr <charles.kerr@canonical.com>
467+ */
468+
469+#include <algorithm>
470+
471+#include <datetime/alarm-queue-simple.h>
472+#include <datetime/clock-mock.h>
473+#include <datetime/engine-eds.h>
474+#include <datetime/planner-range.h>
475+
476+#include <gtest/gtest.h>
477+
478+#include "glib-fixture.h"
479+#include "print-to.h"
480+#include "timezone-mock.h"
481+#include "wakeup-timer-mock.h"
482+
483+using namespace unity::indicator::datetime;
484+using VAlarmFixture = GlibFixture;
485+
486+/***
487+****
488+***/
489+
490+TEST_F(VAlarmFixture, MultipleAppointments)
491+{
492+ // start the EDS engine
493+ auto engine = std::make_shared<EdsEngine>();
494+
495+ // we need a consistent timezone for the planner and our local DateTimes
496+ constexpr char const * zone_str {"Europe/Berlin"};
497+ auto tz = std::make_shared<MockTimezone>(zone_str);
498+ auto gtz = g_time_zone_new(zone_str);
499+
500+ // make a planner that looks at the first half of 2015 in EDS
501+ auto planner = std::make_shared<SimpleRangePlanner>(engine, tz);
502+ const DateTime range_begin {gtz, 2015,7, 1, 0, 0, 0.0};
503+ const DateTime range_end {gtz, 2015,7,31,23,59,59.5};
504+ planner->range().set(std::make_pair(range_begin, range_end));
505+
506+ // give EDS a moment to load
507+ if (planner->appointments().get().empty()) {
508+ g_message("waiting a moment for EDS to load...");
509+ auto on_appointments_changed = [this](const std::vector<Appointment>& appointments){
510+ g_message("ah, they loaded");
511+ if (!appointments.empty())
512+ g_main_loop_quit(loop);
513+ };
514+ core::ScopedConnection conn(planner->appointments().changed().connect(on_appointments_changed));
515+ constexpr int max_wait_sec = 10;
516+ wait_msec(max_wait_sec * G_TIME_SPAN_MILLISECOND);
517+ }
518+
519+ // what we expect to get...
520+ std::array<Appointment,1> expected_appts;
521+ auto appt = &expected_appts[0];
522+ appt->uid = "8ggc30kh89qql8vjumgtug7l14@google.com";
523+ appt->color = "#becedd";
524+ appt->summary = "Hello";
525+ appt->begin = DateTime{gtz,2015,7,1,20,0,0};
526+ appt->end = DateTime{gtz,2015,7,1,22,0,0};
527+
528+ // compare it to what we actually loaded...
529+ const auto appts = planner->appointments().get();
530+ EXPECT_EQ(expected_appts.size(), appts.size());
531+ for (size_t i=0, n=std::min(appts.size(),expected_appts.size()); i<n; i++)
532+ EXPECT_EQ(expected_appts[i], appts[i]);
533+
534+ // cleanup
535+ g_time_zone_unref(gtz);
536+}
537
538=== added file 'tests/test-eds-ics-tzids.ics'
539--- tests/test-eds-ics-tzids.ics 1970-01-01 00:00:00 +0000
540+++ tests/test-eds-ics-tzids.ics 2015-07-22 12:03:21 +0000
541@@ -0,0 +1,56 @@
542+BEGIN:VCALENDAR
543+CALSCALE:GREGORIAN
544+PRODID:-//Ximian//NONSGML Evolution Calendar//EN
545+VERSION:2.0
546+X-EVOLUTION-DATA-REVISION:2015-07-09T17:27:58.908570Z(0)
547+BEGIN:VTIMEZONE
548+TZID:/freeassociation.sourceforge.net/Tzfile/America/Sao_Paulo
549+X-LIC-LOCATION:America/Sao_Paulo
550+BEGIN:STANDARD
551+TZNAME:BRT
552+DTSTART:19700222T000000
553+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=2
554+TZOFFSETFROM:-0200
555+TZOFFSETTO:-0300
556+END:STANDARD
557+BEGIN:DAYLIGHT
558+TZNAME:BRST
559+DTSTART:19701018T000000
560+RRULE:FREQ=YEARLY;BYDAY=3SU;BYMONTH=10
561+TZOFFSETFROM:-0300
562+TZOFFSETTO:-0200
563+END:DAYLIGHT
564+END:VTIMEZONE
565+BEGIN:VTIMEZONE
566+TZID:/freeassociation.sourceforge.net/Tzfile/Europe/Berlin
567+X-LIC-LOCATION:Europe/Berlin
568+BEGIN:STANDARD
569+TZNAME:CET
570+DTSTART:19701025T030000
571+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
572+TZOFFSETFROM:+0200
573+TZOFFSETTO:+0100
574+END:STANDARD
575+BEGIN:DAYLIGHT
576+TZNAME:CEST
577+DTSTART:19700329T020000
578+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
579+TZOFFSETFROM:+0100
580+TZOFFSETTO:+0200
581+END:DAYLIGHT
582+END:VTIMEZONE
583+BEGIN:VEVENT
584+STATUS:CONFIRMED
585+DTSTAMP:20150708T095820Z
586+CREATED:20150708T095820Z
587+UID:8ggc30kh89qql8vjumgtug7l14@google.com
588+SEQUENCE:0
589+TRANSP:OPAQUE
590+SUMMARY:Hello
591+DTSTART;TZID=/freeassociation.sourceforge.net/Tzfile/Europe/Berlin:
592+ 20150701T200000
593+DTEND;TZID=/freeassociation.sourceforge.net/Tzfile/Europe/Berlin:
594+ 20150701T220000
595+LAST-MODIFIED:20150708T095820Z
596+END:VEVENT
597+END:VCALENDAR

Subscribers

People subscribed via source and target branches