Subject: [Ietf-calsify] Issues 8, 68, 69, 70

From: lear at cisco.com (Eliot Lear)
Date: Thu Mar 8 08:57:32 2007

Dear all,

As the jabber session clearly indicates we are having difficulty with 
the many corner cases presented when a local time either occurs twice or 
doesn't occur at all.  The proposals we have seen have the flavors of:

1.  Doctor, it hurts when I hit my head...
2.  Specify what happens in each case (but nobody can agree on what 
happens in each case)

This will be a topic for the working group meeting.  Please have your 
proposals to the mailing list BEFORE the meeting.  We may go with 
something else, but the discussion will go faster if we have good 
starting points.  Failing a resolution in person, we must ask how 
important it is to deal with these DST transitions.

Thanks,

Eliot

---

From: reinhold at kainhofer.com (Reinhold Kainhofer)
Date: Thu Mar 8 15:09:40 2007

Am Donnerstag, 8. M?rz 2007 schrieb Eliot Lear:
> Failing a resolution in person, we must ask how

To be honest, in KOrganizer and libkcal (which is used in all KDE applications 
that use calendars to any extent), we don't care about the transitions at 
all, so this is not a real issue for us. It's just an issue that a 
specification still needs to deal with...

Chers,
Reinhold

- -- 
- ------------------------------------------------------------------
Reinhold Kainhofer, Vienna University of Technology, Austria
email: [email-masked], http://reinhold.kainhofer.com/
 * Financial and Actuarial Mathematics, TU Wien, http://www.fam.tuwien.ac.at/
 * K Desktop Environment, http://www.kde.org, KOrganizer maintainer
 * Chorvereinigung "Jung-Wien", http://www.jung-wien.at/

---

From: lennox at cs.columbia.edu (Jonathan Lennox)
Date: Wed Mar 14 07:50:20 2007

On Thursday, March 8 2007, "Eliot Lear" wrote to "[email-masked]" saying:

> doesn't occur at all.
> proposals to the mailing list BEFORE the meeting.

For the sake of the working group meeting, here's a taxonomy of possible
solutions for local time discontinuities.  I don't have a single concrete
proposal at this point, but I think this will help move our discussion of
possible solutions forward.

I will first discuss the types of local time discontinuities and various
possible ways of resolving them, and then discuss the ways that they can
arise.  (It may well be that the group decides on different resolutions for
discontinuities that arise in different ways.)

There are two types of discontinuities: repeated times ("fall back") and
skipped times ("spring forward").

Repeated times: local wall-clock values that occur more than once.
         E.g.: 2007-11-04 01:30:00 America/New_York.

Possible solutions:
R1.  Repeated time values are interpreted as the first occurence of the
repeated time.
         E.g.: 2007-11-04 01:30:00 EDT = 2007-11-04 05:30:00 UTC

R2.  Repeated time values are interpreted as the final occurence of the
repeated time.
         E.g.: 2007-11-04 01:30:00 EST = 2007-11-04 06:30:00 UTC

R3.  Events represented by repeated time values take place at every
occurence of the repeated time.

R4.  Repeated time values are interpreted as an unspecified occurence
of the repeated time.

R5.  Repeated time values are interpreted as an an unspecified time in
time in the range [R1 - R2].

R6.  Repeated time values are completely unspecified, and intepreters can
treat them however they like.

R7.  Repeated time values are forbidden, and interpreters MUST reject any
iCalendar document specifying them.

(Note that in obscure situations, involving buggy VTIMEZONE definitions or
particularly crazy legislatures, local wall-clock values can actually occur
three or more times, not just twice.  I've worded my solutions above to take
this into account.)

Skipped times: local wall-clock values that do not occur.
        E.g.: 2007-03-11 02:30:00 America/New_York.

Possible solutions:
S1.  Skipped time values are interpreted as the instant of the
discontinuity which skipped the time.
       E.g.: 2007-03-11 03:00:00 EDT = 2007-03-11 07:00:00 UTC
       (Note that this is one second after
             2007-03-11 01:59:59 EST = 2007-03-11 06:59:59 UTC.)

S2.  Skipped time values are interpreted using the UTC offset from before
the discontinuity.
       E.g.: 2007-03-11 02:30:00 "EST" (UTC-5) = 2007-03-11 07:30:00 UTC =
             2007-03-11 03:30:00 EDT

S3.  Skipped time values are interpreted using the UTC offset from after
the discontinuity.
       E.g.: 2007-03-11 02:30:00 "EDT" (UTC-4) = 2007-03-11 06:30:00 UTC =
             2007-03-11 01:30:00 EST

S4.  Events represented by skipped time values do not take place.

S5.  Skipped time values are interpreted as an unspecified instance of {S3,
S2}.

S6.  Skipped time values are interpreted as an unspecified instance of {S3,
S1, S2}.

S7.  Skipped time values are interpreted as an unspecified time in the
range [S3 - S2].

S8.  Skipped time values are completely unspecified, and intepreters can
treat them however they like.

S9.  Skipped time values are forbidden, and interpreters MUST reject any
iCalendar document specifying them.

There are also several ways that discontinuous times can arise in
iCalendar.  I've described these by their issue numbers in Calsify issue
tracker, breaking down further where necessary.

I68: Discontinuous times explicitly specified in an iCalendar document,
other than in an VTIMEZONE (where they're well-defined by 2445).
      DTSTART;TZID=America/New_York:20070311T023000
      
      DTEND;TZID=America/New_York:20071104T013000

I69: Discontinuous times that arise as a recurrence instance's start time.
        DTSTART;TZID=America/New_York:20070310T023000
        RECUR:FREQ=DAILY;COUNT=2
        
        The first occurence of this event is well-defined, taking place at
        2007-03-10 02:30:00 EST; the event's second occurence is
        problematic.

I70a1: Discontinuous times that arise because of a nominal event duration,
offset from an explicit time.
        DTSTART;TZID=America/New_York:20070310T023000
        DURATION:P1D

        The start time of this event is well-defined, taking place at
        2007-03-10 02:30:00 EST; the event's end time is problematic.

I70a2: Discontinuous times that arise because of a hybrid nominal/accurate
event duration, offset from an explicit time.
        DTSTART;TZID=America/New_York:20070310T023000
        DURATION:P1DT8H

        The start time of this event is well-defined, taking place at
        2007-03-10 02:30:00 EST; the event's end time is problematic. 

I70b1: Discontinuous times that arise because of a nominal event duration,
offset from a recurrence instance's start time.
        DTSTART;TZID=America/New_York:20070309T023000
        DURATION:P1D
        RECUR:FREQ=DAILY;COUNT=2

        The first occurence of this event lasts from 2007-03-09 02:30:00 EST
        to 2007-03-10 02:30:00 EST.  The second occurence starts at
        2007-03-10 02:30:00 EST, but its end time is problematic.

I70b2: Discontinuous times that arise because of a hybrid nominal/accurate
event duration, offset from a recurrence instance's start time.
        DTSTART;TZID=America/New_York:20070309T023000
        DURATION:P1DT8H
        RECUR:FREQ=DAILY;COUNT=2

        The first occurence of this event lasts from 2007-03-09 02:30:00 EST
        to 2007-03-10 10:30:00 EST.  The second occurence starts at
        2007-03-10 02:30:00 EST, but its end time is problematic.

I8/I68: A nominal duration starting from an explicitly-specified
discontinuous time.
      DTSTART;TZID=America/New_York:20070311T023000
      DURATION:P1D

      The naively-calculated end time, 2007-03-12 02:30:00 EDT, is
      well-defined, but this may be surprising based on the resolution of
      the start time.

I8/I69: A nominal duration starting from a discontinuous recurrance instance
start time.
      DTSTART;TZID=America/New_York:20070310T023000
      RECUR:FREQ=DAILY;COUNT=2
      DURATION:P1D

      The naively-calculated end time of the second occurence, 2007-03-12
      02:30:00 EDT, is well-defined, but this may be surprising based on the
      resolution of the start time.

I hope this is helpful.

-- 
Jonathan Lennox
[email-masked]

---

From: Nigel.Swinson at rockliffe.com (Nigel Swinson)
Date: Fri Mar 16 08:22:08 2007

> possible solutions forward.

I propose we deal with this as follows:
- A date-time landing in a spring forward period uses the utc-offset in 
effect before the TZ change
- A date-time landing in a fall back period uses the utc-offset in effect 
before the TZ change.
- If you want to distinguish between the two date-times resulting from a 
fall-back period, you should write your rule WRT to a TZ that doesn't use 
DST like in plain UTC.  (Vent poisionous gasses every hour etc)
- local date-times can and should be validated before storage, and during 
recurrence expansion such that times in the spring forward period are always 
corrected.

A commentary of Jonathan's helpful discussion to see how this works out in 
practice.

======================================
>         E.g.: 2007-11-04 01:30:00 EDT = 2007-11-04 05:30:00 UTC

This one, as this 1:30 EDT always turns into 5:30 UTC, never 6:30 UTC.

>         E.g.: 2007-11-04 01:30:00 EST = 2007-11-04 06:30:00 UTC

No, cos I think recurrence sets have to be stored as local time, so BYHOUR 
works properly, and 1:30 EST won't turn into 6:30 UTC.

> occurence of the repeated time.

No.  You'd use UTC or a TZ with no DST if you wanted there to be two.

> R4.  Repeated time values are interpreted as an unspecified occurence

I'm fine with unspecified, I don't mind if implementations aren't fully 
interoperable here, and it would allow me to choose R1.

> time in the range [R1 - R2].

If I fully understand this, which I'm not sure I do, then I don't like this 
as I don't think it makes a lot of sense. (!!?!!)  More helpfully it sounds 
like it might change the minutes of the time which I think is bad.

> treat them however they like.

Fine, allows we to choose R1 yes?

> iCalendar document specifying them.

I don't think this is practical.  It seems very easy to create a rule that 
would naievely create repeated times, but with my proposal you can't get 
duplicated times, as "1:30 EDT always turns into 5:30 UTC, never 6:30 UTC".

======================================
>        E.g.: 2007-03-11 02:30:00 America/New_York.

I think the solution here is fairly arbitrary, my personal opinion is that 
S2 is what most would expect, but I'm happy if the behaviour is undefined.

>             2007-03-11 01:59:59 EST = 2007-03-11 06:59:59 UTC.)

No. I think you are proposing that 02:34 EDT becomes 03:00 EDT.  I don't 
like the suggestion that we would change the seconds/minutes.

>       E.g.: 2007-03-11 02:30:00 "EST" (UTC-5) = 2007-03-11 07:30:00 UTC =

Yes

>       E.g.: 2007-03-11 02:30:00 "EDT" (UTC-4) = 2007-03-11 06:30:00 UTC =

No

> S4.  Events represented by skipped time values do not take place.

Definately not.

> S5.  Skipped time values are interpreted as an unspecified instance of 

Ok, I'll choose S2

> S6.  Skipped time values are interpreted as an unspecified instance of 

No

> S7.  Skipped time values are interpreted as an unspecified time in the

No, same reason as S1

> treat them however they like.

Ok, I'll choose S2

> iCalendar document specifying them.

I don't think this is practical

======================================
> tracker, breaking down further where necessary

You effectively call this on each instance to correct for leap forward 
periods.

TimeZone::Adjust() {
 // ToUtc will fix any leap forward problems, and FromUtc will take us back
 FromUtc(ToUtc());
}

>      DTSTART;TZID=America/New_York:20070311T023000

Convert to UTC using winter time.  Adjust() would move this to 
20070311T033000.

It is obviously going to be helpful if clients make their best efforts to 
prevent creation of times like this.

>      DTEND;TZID=America/New_York:20071104T013000

Convert to UTC using summer time. Adjust() would leave this as 
20071104T013000.

>        2007-03-10 02:30:00 EST; the event's second occurence is

Date arithmetic (as opposed to time arithmetic) can/should be done without 
timezones, so:

Adjust(20070310T023000 + 2D)
=Adjust(20070310 + 2D + T023000)
=Adjust(20070312 + T023000)
=Adjust(20070312T023000)
=20070312T023000

>        2007-03-10 02:30:00 EST; the event's end time is problematic.

1D means end at 02:30 and Adjust() moves it to T033000

>        2007-03-10 02:30:00 EST; the event's end time is problematic.

+1D first, then +8H then Adjust means,
=Adjust(20070310T023000 + 1D + 8H)
=Adjust(20070311T023000 + 8H)
=Adjust(20070311T113000) (we've added 9 hours because of the DST, I suggest 
date-time arithmetic always done in UTC)
=20070311T113000

>        2007-03-10 02:30:00 EST, but its end time is problematic.

Adjust means end time is T033000

>        2007-03-10 02:30:00 EST, but its end time is problematic.

As for I70a2, end time is 20070311T113000

>      well-defined, but this may be surprising based on the resolution of

I think we apply the duration before we Adjust().  As above, I think the 
user expects the appointment to finish at 2:30, and probably didn't think 
about DST when they created it.  If we Adjust() then apply duration calling 
Adjust() on the end time, then that means it'll start and end at 3:30am.  So 
I think the naively-calculated end time is correct. It is obviously going to 
be helpful if clients make their best efforts to prevent creation of times 
like this.

>      resolution of the start time.

Again I think we apply the duration before we call Adjust(), but our 
recurrence set is based on days.  I'll presume count was 4 as it's 
interesting:

1) 20070310T023000-20070311T033000 (Adjust() Fixed endtime)
2) 20070311T033000-20070312T023000 (Applied duration before Adjust() fixed 
starttime)
3) 20070312T023000-20070313T023000 (What the user was really expecting)
4) 20070313T023000-20070314T023000

It's probably worth restating that the user can always enter their 
recurrence rule WRT to UTC should this kind of oddity not be as they would 
like.  Then if you are viewing the calender WRT to EST you'll get two 
recurrences at the same time WRT to that timezone, but on closer examination 
you'd see the start time was different WRT to UTC.

> I hope this is helpful.

It was thanks!  It made me realise that my CLocalTime::operator+ when adding 
45 mins, could possibly return a localtime than was before the source time 
potentially resulting in an infinite loop!

Nigel

---

From: lennox at cs.columbia.edu (Jonathan Lennox)
Date: Fri Mar 16 09:52:02 2007

> - A date-time landing in a fall back period uses the utc-offset in effect 

This is probably the simplest fully-specified definition for
discontinuities.

The one problem with it is the following:
DTSTART;TZID=America/New_York:20070311T023000
DTEND;TZID=America/New_York:20070311T031500

The DTSTART is non-existent, falling during the spring-forward period; the
DTEND is well-defined.

Under your proposal, this event's end time would end up before its start
time.   Its start time evaluates as 2007-03-11 02:30:00 "EST" (UTC-5) =
2007-03-11 07:30:00 UTC = 2007-03-11 03:30:00 EDT, but its end time is
2007-03-11 03:15:00 EDT, 15 minutes earlier.

(This is analogous to the problem you discovered with your operator+.)

Do we care about this corner case of a corner case?  Should we just define
such odd outcomes as zero-duration events?

The other "corner-case squared" we have to worry about is
    DTSTART;TZID=Pacific/Kiritimati:19950101T090000
    DURATION:P1D
In the 90s, the Pacific nation of Kiribati (the Gilbert Islands, before
independence) decided it was tired of having the International Date Line
split the country in two.  Thus, its eastern island groups switched from
UTC-11/UTC-10 to UTC+13/UTC+14, skipping January 1, 1995.  (These are the
Olsen zones Pacific/Enderbury and Pacific/Kiritimati, respectively.)

In this case, a P1D nominal duration would presumably last zero time, and a 
DAILY recurrence would have two simultaneous occurences.  A similar odd
VTIMEZONE definition could potentially result in nominal durations coming
out as negative elapsed time.  Again, do we care?

-- 
Jonathan Lennox
[email-masked]

---

From: Nigel.Swinson at rockliffe.com (Nigel Swinson)
Date: Fri Mar 16 11:21:36 2007

> such odd outcomes as zero-duration events?

I think it falls into the category of "the client should make every effort 
not to create events with date-times that land in the leap forward period" 
and then go on to recommend how we handle them.  I think we handle the above 
event just like any other event that has a DTEND before the DTSTART. 
Surprisingly I can't find existing recommendation on this subject, but I 
suggest we "fix" DTEND by moving it to match DTSTART, or by ignoring DTEND 
as invalid, which would have the same effect.  ie yes, define them as 
zero-duration events. :o)

> out as negative elapsed time.  Again, do we care?

I guess +1D would land you on a date that existed in the gigantic leap 
forward period between -11/-10 and +13/+14.  We'd then convert to UTC 
using -11/-10, and then back to local time using +13/+14.  After adding the 
next +1D, we'd have left the leap forward period, and entered +13/+14 proper 
and now Adjust() would become a noop again.

So 19941231 had -10, and they jumped to +14, therefore the clock went from:
DTSTART;TZID=Pacific/Kiritimati:19941231T235959 => DTSTART;19950101T095959Z
DTSTART;TZID=Pacific/Kiritimati:19950102T000000 <= DTSTART;19950101T100000Z

So with
DTSTART;TZID=Pacific/Kiritimati:19941230T090000
DURATION:P1D
RECUR:FREQ=DAILY

Instance 1)
19941230T090000-19941231T090000

Instance 2)
Start:19941231T090000
End:
Adjust(19941231T090000 + 1D)
Adjust(19950101T090000)
FromUtc(19950101T190000Z) (In leap forward period, so ToUtc uses UTC -10)
19950102T090000 (After TZ switch, so now use UTC +14)

Gives:
19941231T090000-19950102T090000

Instance 3)
Start:
19941231T090000 + 1D = 19950102T090000
End
19941231T090000 + 2D
19950102T090000

Gives:
19950102T090000-19950102T090000

Instance 4)
19950102T090000-19950103T090000

The set is therefore:
19941230T090000-19941231T090000
19941231T090000-19950102T090000  - Appears to span two days
19950102T090000-19950102T090000  - The oddity which describes an instant 
rather than a day.
19950102T090000-19950103T090000

I'd be happy enough with these rules.  Seems to work ok?  Remembering again 
they could have used P24H instead of 1D, or specified the rule in UTC to get 
a differerent potentially more desirable effect.

Nigel