Appointment in calendars use wrong time from ics file - icalendar

I am generating a .ics file. When I import it to a calendar app (such as the on on OSX or iOS) it says:
20:00 to 21:00
18:00 to 19:00 (GMT)
But I need to have the time of the appointment to be 18:00 to 19:00 by default (GMT time). How can I do it?
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:xxx
X-WR-TIMEZONE:Europe/Zurich
X-WR-CALDESC:
BEGIN:VTIMEZONE
TZID:Europe/Zurich
X-LIC-LOCATION:Europe/Zurich
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
TZNAME:CEST
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
TZNAME:CET
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
Event:
BEGIN:VEVENT
DTSTART:20140929T180000Z
DTEND:20140929T190000Z
DTSTAMP:20141001T223333Z
UID:542c651df4095
DESCRIPTION:Keine
SUMMARY:Mindblowers
LOCATION:
URL;VALUE=URI:xxx
END:VEVENT

most calendar applications will display in the timezone that you have set in the app. So to see times in GMT time, set the timezone of the app to GMT.
Alternatively you may not really be meaning that you want 18:00 to 19:00 (GMT) but that you want 18:00 to 19:00 no matter what timezone the app is in. This is called a 'floating time' (like an alarm that wakes you at 7am no matter what city or timezone you are in, no at 7am back home).
https://www.rfc-editor.org/rfc/rfc5545#page-32
For example, the following represents January 18, 1998, at
11 PM:
19980118T230000
DATE-TIME values of this type are said to be "floating" and are
not bound to any time zone in particular. They are used to
represent the same hour, minute, and second value regardless of
which time zone is currently being observed.

Related

How to fix incorrect Date due to timezone in Core Data from using Calendar.current.startOfDay?

I have erroneously used Calendar.current.startOfDay(for: Date()) to populate a date attribute in Core Data. This means that when users cross different timezones I may have different dates unintentially stored in the date attribute field e.g.
Timezone 1 - 25th 23:00
Timezone 2 - 25th 22:00
Timezone 3 - 26th 05:00
I need to update the Calendar to use UTC Timezone but I need to also perform a migration so that the existing entries in Core Data read like this…
Result:
Timezone 1 - 26th 00:00
Timezone 2 - 26th 00:00
Timezone 3 - 26th 00:00
What are the steps to perform this migration. If I do a UTC startOfDay on it Timezone 1 would get 25th 00:00 instead of 26th 0:00 which is what it should be. Is it possible to accurately update existing entries?
Edit:
For some context I need a reliable way to get all the entries for the 26th for example. I used startOfDay to store the date as it meant I could query by it too and have the relevant entry returned (at any moment in time get the startOfDay and it will give me the entries for the whole day). For historical dates I can do the same - let's say the user has navigated back 2 days I can take startOfDay and subtract 2 days using Calendar.current.date(byAdding: .day, value: -2, to: date) and query for that.
So now the timezone breaks the above logic but is there some way to fix this? If I loop through the entries I can figure out the date it was supposed to be for and perhaps change the attribute to a string - e.g. 26-05-2021 or start to store day, month, year instead and query that.
From reading your answer Duncan I don't think I want to use UTC calendar as it would start to store the entry against the incorrect date from the users perspective dependent on their timezone e.g. user moves to next day and utc is still on previous.
Edit 2:
In a migration I will take the date that is stored and map it to new day, month and year properties storing those instead by getting them from Calendar.current.dateComponents([.day, .month, .year], from: date). Then instead of query by date I will query by day month and year of the Calendar.current where the user is. The side effect here is there is potential the user adds something for today (27th) changes timezone and sees 26th data but I don't think it can be avoided and the old data will then show as intended.
If you took the current time and used Calendar.current.startOfDay(for: Date()) to calculate midnight in the user's local time zone, you have a loss of information. You don't know what time of day the operation was performed. If you saved the time of day in the local time zone in another field, you could reconstruct a Date in UTC.
It isn't clear that what you did was wrong. The day, month, and year is only meaningful in a specific time zone. I am in the Washington DC metro area. We are in daylight savings time (EDT). It is currently 20:56 on the 26th of May. However, it's 1:56 AM on the 27th of May in London, 2:57 AM in Munich, and 3:57 AM in Tel Aviv. All at the exact same instant in time. In UTC it is 0:57 AM on the 27th of May.
Most people think of the calendar date in their local time zone. That is their frame of reference. If you ask me the date right now, I'll tell you it's the evening of the 26th of May. Unless I know you are in a different time zone, that's the "right" answer to me.
If I start out at midnight on a given day in my time zone, calling Calendar.current.startOfDay(for: Date()) each hour, I'll get midnight that day for all 24 hours in my local time zone. For the first 20 hours of the day, that would be the same result I would get if I created a Calendar in UTC and made the same call. However, at 20:00 EDT, I would start getting the next calendar day if I made the same query in UTC.
If you don't know what time of day you made the call to Calendar.current.startOfDay(for: Date()), there is no foolproof to figure out the day/month year in UTC at the instant you made the call. It depends on the time of day in the local timezone, and that timezone's offset from UTC.
Consider this code:
var calendarUTC = Calendar(identifier: .gregorian)
if let utcTimeZone = TimeZone(identifier: "UTC") {
print("Valid time zone")
calendarUTC.timeZone = utcTimeZone
}
print ("Start of day in UTC is \(calendarUTC.startOfDay(for: Date()))")
print ("Start of day in local time zone is \(Calendar.current.startOfDay(for: Date()))")
That outputs:
Start of day in UTC is 2021-05-27 00:00:00 +0000
Start of day in local time zone is 2021-05-26 04:00:00 +0000
That's because right now, which is 20:56 on 26 May in my time zone, it's 0:56 on 27 May in UTC. So if I ask the UTC calendar for the start of day for now (Date()) I get midnight on 27 May, in UTC.
If I ask the same question of my local calendar, I get midnight on 26 may in my time zone, which is 4:00 AM on 26 May in UTC.
If I ran the same code this morning at 8:00 AM in my time zone, I would have gotten the output:
Start of day in UTC is 2021-05-26 00:00:00 +0000
Start of day in local time zone is 2021-05-26 04:00:00 +0000
(Since at 8:00 AM on 26 May in EDT is also 26 May in UTC.)
It's tricky and not 100% reliable and only works if you know that all days were created using startOfDay. But first you need to decide what you want. Say one date was created at 10pm in the New York, and one at exactly the same moment in London, at 4am the next day. What day do you want to be stored?
If your date stored is 25th, 10pm, then you know it was created in a timezone where the day started at 10pm UTC. You are lucky, there are only two time zones that would have created this, one without DST, one with DST. So you know it happened in one of these two time zones, within 24 hours.
Unfortunately, time zones cover 26 hours. Fortunately, only some islands in the Pacific Ocean have same time and different dates (+13 and -11 hours). For these places, you cannot possibly know which date is correct, but very few people would be affected.

Some of deleted occurrence of recurring event doesn't comes under EXDATE

BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
SUMMARY:Test
TRANSP:OPAQUE
ATTENDEE;CUTYPE=INDIVIDUAL;EMAIL=a#icloud.com;PARTSTAT=ACCEPTED;
ROLE=CHAIR;CN=a:/aMzg2Mzc2MTQzODYzNzYxNBljuJkfI_9Sr7UoBKqc9uB4hzRY_BLyjaYyqorZZI2N/principal/
ATTENDEE;CUTYPE=INDIVIDUAL;EMAIL=jag#icloud.com;
PARTSTAT=ACCEPTED;X-CALENDARSERVER-DTSTAMP=20170629T173339Z;CN=jag:/aNDM3NzY5NTU0Mzc3Njk1NYeGQfswrR4swF97f86hXgEy6_Ht3psyYKknwa5ed2iV/principal/
UID:4CF18F94-CFB0-4EC8-8CA3-13BD88BE3009
DTSTART;TZID=America/Los_Angeles:20170530T183000
DTEND;TZID=America/Los_Angeles:20170530T220000
RRULE:FREQ=WEEKLY
EXDATE;TZID=America/Los_Angeles:20170711T183000
EXDATE;TZID=America/Los_Angeles:20170627T183000
EXDATE;TZID=America/Los_Angeles:20170620T183000
END:VEVENT
BEGIN:VEVENT
SUMMARY:Test
TRANSP:OPAQUE
ATTENDEE;CUTYPE=INDIVIDUAL;EMAIL=a#icloud.com;PARTSTAT=ACCEPTED;
ROLE=CHAIR;CN=a: /aMzg2Mzc2MTQzODYzNzYxNBljuJkfI_9Sr7UoBKqc9uB4hzRY_BLyjaYyqorZZI2N/principal/
ATTENDEE;CUTYPE=INDIVIDUAL;EMAIL=jag#icloud.com;
PARTSTAT=DECLINED;X-CALENDARSERVER-DTSTAMP=20170629T173339Z;
CN=jag:/aNDM3NzY5NTU0Mzc3Njk1NYeGQfswrR4swF97f86hXgEy6_Ht3psyYKknwa5ed2iV/principal/
UID:4CF18F94-CFB0-4EC8-8CA3-13BD88BE3009
DTSTART;TZID=America/Los_Angeles:20170606T183000
DTEND;TZID=America/Los_Angeles:20170606T220000
RECURRENCE-ID;TZID=America/Los_Angeles:20170606T183000
END:VEVENT
END:VCALENDAR
Here, I have weekly recurring meeting for every Tuesday from 6:30 PM to 10:00 PM. I have deleted the single occurrence for 06/06/2017. But when I fetch meetings it gives deleted occurrence i.e 06/06/2017 6:30 PM to 10:30 PM which it shouldn't be. While 20/06, 27/06 and 11/07 comes in ex date which is fine. My question is that why 06/06 is not in ex date even after deletion like other deleted dates ?
Thanks in advance

iCalendar timezone definition for DST period

By definition European Summer Time begins at last Sunday of March and ends by last Sunday of October
see: https://en.wikipedia.org/wiki/Summer_Time_in_Europe
iCalendar event generated from thunderbird's lightning calendar use this definition of timezone with timestamps from year 1970
BEGIN:VTIMEZONE
TZID:Europe/Prague
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
TZNAME:CEST
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
TZNAME:CET
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
END:STANDARD
END:VTIMEZONE
Since last Sunday of March and October probably won't be the same day every year, shouldn't there be different date every year?
For example for 2016:
BEGIN:VTIMEZONE
TZID:Europe/Prague
BEGIN:DAYLIGHT
...
DTSTART:20160327T020000
...
END:DAYLIGHT
BEGIN:STANDARD
...
DTSTART:20161030T030000
...
END:STANDARD
END:VTIMEZONE
Is it right or am I missing something?
The DTSTART indicates the start date, but after that RRULE is used to calculate all the next occurences.
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
This means:
Recur every year
On every 3rd month
On the last sunday of that month

Convert from wrong unix time stamp to correct

I've inherited a problem. A front end calendar application that I have to update is treating every event as being in unix time. No matter what timezone the calendar is meant to be displayed in.
Our DB saves every event as unix time.
The calendar will assume that if I create an event at 7:00 PM it is 7:00 PM UTC. How would I go about converting this from 7:00 PM UTC to 7:00 PM [selected timezone] so that when it gets to the DB it'll be saved in the proper unix time stamp.
Tools available: Moment (with timezone), jquery.

FQL and business hours

I'm querying information from a Facebook page for a small business using FQL and I'm trying to parse the business hours. The numbers I am getting back seem to represent seconds but I'm not sure when the epoch is. Wednesday and Thursday are the most confusing - open on Thursday is "57600" which would be 16 hours in seconds which would make 4pm Wednesday the epoch, but the closing hours on Wednesday - far past 4- are in the 600,000+ range.
Mon: 8:15am-12pm and 1pm - 5pm Tue: 8am-12pm and 1pm - 5pm Wed: 8am-12pm and 1pm - 9pm Thur:8am-12pm and 1pm - 5pm Fri:8am-12pm and 1pm - 5pm Sat:8am-12pm and 1pm - 5pm
<hours>
<mon_1_open>404100</mon_1_open>
<mon_1_close>417600</mon_1_close>
<tue_1_open>489600</tue_1_open>
<tue_1_close>504000</tue_1_close>
<wed_1_open>576000</wed_1_open>
<wed_1_close>590400</wed_1_close>
<thu_1_open>57600</thu_1_open>
<thu_1_close>72000</thu_1_close>
<fri_1_open>144000</fri_1_open>
<fri_1_close>158400</fri_1_close>
<sat_1_open>230400</sat_1_open>
<sat_1_close>244800</sat_1_close>
<sun_1_open>0</sun_1_open>
<sun_1_close>0</sun_1_close>
<mon_2_open>421200</mon_2_open>
<mon_2_close>435600</mon_2_close>
<tue_2_open>507600</tue_2_open>
<tue_2_close>522000</tue_2_close>
<wed_2_open>594000</wed_2_open>
<wed_2_close>622800</wed_2_close>
<thu_2_open>75600</thu_2_open>
<thu_2_close>90000</thu_2_close>
<fri_2_open>162000</fri_2_open>
<fri_2_close>176400</fri_2_close>
<sat_2_open>248400</sat_2_open>
<sat_2_close>262800</sat_2_close>
<sun_2_open>0</sun_2_open>
<sun_2_close>0</sun_2_close>
</hours>
If I change it to simply 8am-5pm Monday to Saturday I get an equally confusing response from FB
<hours>
<mon_1_open>403200</mon_1_open>
<mon_1_close>435600</mon_1_close>
<tue_1_open>489600</tue_1_open>
<tue_1_close>522000</tue_1_close>
<wed_1_open>576000</wed_1_open>
<wed_1_close>608400</wed_1_close>
<thu_1_open>57600</thu_1_open>
<thu_1_close>90000</thu_1_close>
<fri_1_open>144000</fri_1_open>
<fri_1_close>176400</fri_1_close>
<sat_1_open>230400</sat_1_open>
<sat_1_close>262800</sat_1_close>
<sun_1_open>0</sun_1_open>
<sun_1_close>0</sun_1_close>
<mon_2_open>0</mon_2_open>
<mon_2_close>0</mon_2_close>
<tue_2_open>0</tue_2_open>
<tue_2_close>0</tue_2_close>
<wed_2_open>0</wed_2_open>
<wed_2_close>0</wed_2_close>
<thu_2_open>0</thu_2_open>
<thu_2_close>0</thu_2_close>
<fri_2_open>0</fri_2_open>
<fri_2_close>0</fri_2_close>
<sat_2_open>0</sat_2_open>
<sat_2_close>0</sat_2_close>
<sun_2_open>0</sun_2_open>
<sun_2_close>0</sun_2_close>
</hours>
Am I missing some defacto standard time representation? How would someone go about parsing this as a legitimate time of day?
The Unix epoch is the time 00:00:00 UTC on 1 January 1970. Any time you see the term "epoch" used in relation to computer-based time, that's usually what it means.
In UTC, 404100 is Mon, 05 Jan 1970 16:15:00 GMT. Or, in the PST timezone, Mon, 05 Jan 1970 08:15:00 PST, which is the time you're expecting. Ignore the date; it's irrelevant, anyways.
You can test what I'm describing using this Epoch Converter.