In a world of regular binary systems mapped on to an equally regular decimal counting system, the way we describe Time is like the ‘crazy’ outsider refusing to accept that the world has moved on.
60 seconds; 60 minutes; 24 hours; 28, 30 or 31 days; 365 and a bit days. Time Zones that are as much political as geographically sensible. Then throw in Daylight Saving and you have a recipe for complete confusion.
Here at Cronofy we have chosen to embrace dealing with time and handle as many of the complexities as we can on behalf of our customers. However our customers can’t ignore time when it comes to interating with user’s calendars. So part of our role is to provide guidance and documenting how to achieve reliable behaviour.
At one side you have your application. This is usually describing times to the user in their local time zone.
Next you have the Cronofy API handling all of the interactions, syncrhonization and privacy for your application with all of the calendar servers.
Then you have the Calendar Server (Google, Exchange, Apple, Office 365, etc). Whilst there is generally not much interpretation that happens apart from filtering, they each have certain constraints as to how they’ll accept time being represented.
On the other side you have the Calendar Client (Outlook, Apple Calendar, etc) that the user actually interacts with. This will convert the time stored in the Calendar Server and/or position the event into the user’s local time zone.
Time Zones are a method of localising times such that 9am can have a common meaning across a geographical area. A meaning that relates more closely to the cadence of sunrise, sunset, the working day, local customs, etc. These are identified in the IANA Time Zone Database, mostly, with a
There are other ways to describe them but the IANA descriptors are the most widely used and what we’ve standardized on here at Cronofy.
Another description you may see is Offset from Greenwich Mean Time (GMT). New York would generally be descibed as GMT-05:00. From a straight math point of view this sounds appealing however daylight saving means that the offset isn’t always consistent. Beware of using this as a means of calculating time in your application.
Daylight saving is generally implemented as move forward or back of local time, relative to GMT. So New York can either be offset by 5 or 4 hours from GMT depending on the time of year. If the UK and the US switched to daylight saving at the same time (they don’t) then the local to local time offset would remain the same. However offsets are described against GMT which doesn’t change as a reference so the number of hours you need to add does change. Especially challenging when you’re dealing with future dates.
There is a 3 or 4 letter acronym that is generally used to indicate which time zone and whether daylight saving is in place.
City descriptors described above also serve as lookups for the current application of daylight saving. The transition times do change, sometimes from year to year, depending on decisions made by local governments. The IANA Database coordinates these changes to ensure systems are up to date. Cronofy keeps our IANA Databse very up to date :).
To allow times to be compared, UTC is a common time representation that dispenses with time zones. It happens that this coincides with GMT. There is also a common representtion format, ISO8601.
Midday in London on the 9th November corresponds to
2016-11-09T12:00:00Z. Whereas midday in London on 9th August, when daylight saving does apply in the UK, corresponds to
In New York on the same day in November, midday corresponds to
2016-11-09T17:00:00Z and in August
2016-08-09T16:00:00Z as the US also observes daylight saving.
In Singapore however, where daylight saving is not used, midday on 9th November is
2016-11-09T04:00:00Z and is at the same UTC time in August
You’ll note the
Z suffix at the end of the time values. This indicates that the time is UTC.
There are two types of interaction that involve time, querying and creating/updating events.
Queries for data like events and free busy slots are conducted using the data parameters
to on the Cronofy API. These dates are considered ‘exlusive end’, ie the results returned will be up to but not including the value of
to.There is an additional paramter
tzid that is used to control how the
to parameters are interpreted.
Etc/UTC is passed as the
tzid parameter is used then the query is conducted using midnight to midnight UTC eg:
2016-11-09 and a
2016-11-17 would result in a list of records from
2016-11-09T00:00:00Z and before
America/New York was passed as the
tzid parameter then the query is conducted using midnight to midnight New York time eg:
2016-11-09 and a
2016-11-17 would result in a list of records from
2016-11-09T05:00:00Z and before
This ensures that you can specify the local day boundaries to meet your applications purposes.
Cronofy has standardised on UTC representation of times for describing event times. So all event times must be first converted to UTC before being submitted to our API.
"start" : "2016-11-09T09:00:00Z",
"end" : "2016-11-09:10:00:00Z",
In order to provide localization info to the Calendar Client we also support a
tzidattribute on events. So whilst the the UTC version of the time may be confusing to a user, adding time zone information allows the Calendar Client to correctly localize it.
For example a one hour event at 6pm Los Angeles time on 15th November would be represented as:
"start" : "2016-11-16T02:00:00Z",
"end" : "2016-11-16T03:00:00Z",
"tzid" : "America/Los Angeles",
tzid would still mean that the event was rendered at the correct position in the user’s calendar. However when they opened the event, it is likely that they would see the time as 2am the following day.
It is also possible to specify a different
tzid value for both
end times. Useful when describing flights for instance. More information in our API documentation.
We’ve tried to collate some useful examples in different coding languagues.
zone = ActiveSupport::Time Zone['America/Los Angeles']
start = zone.local(2016,11,15,18,0,0) # => Tue, 15 Nov 2016 18:00:00 PST -08:00
start.utc # => 2016-11-16 02:00:00 UTC
start.utc.iso8601 # => "2016-11-16T02:00:00Z"
$timezone = new DateTimeZone("America/Los_Angeles");
$date = new DateTime("2016-11-15 18:00:00", $timezone);
// => Tue, 15 Nov 2016 18:00:00 -0800
// => Wed, 16 Nov 2016 02:00:00 +0000
// => 2016-11-16T02:00:00+0000
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("America//Los_Angeles");
DateTimeOffset localTime = new DateTimeOffset(new DateTime(2016, 11, 15, 18, 0, 0), easternZone.BaseUtcOffset);
/* Tue, 15 Nov 2016 18:00:00 PST -08:00 */
DateTimeOffset utcTime = localTime.ToUniversalTime();
/* 2016 - 11 - 16 02:00:00 UTC */
We hope you’ve found this guide useful. Please email firstname.lastname@example.org if anything isn’t clear or you have any suggestions for amendments of additions.