Logo Search packages:      
Sourcecode: libical version File versions  Download package

int icaltimezone_get_utc_offset ( icaltimezone *  zone,
struct icaltimetype *  tt,
int *  is_daylight 

This API wasn't updated when we changed icaltimetype to contain its own timezone. Also, this takes a pointer instead of the struct.

Definition at line 810 of file icaltimezone.c.

References icaltimezone_adjust_change(), icaltimezone_compare_change_fn(), icaltimezone_find_nearby_change(), and utc_timezone.

Referenced by icaltimezone_convert_time().

    icaltimezonechange *zone_change, *prev_zone_change, tt_change, tmp_change;
    int change_num, step, utc_offset_change, cmp;
    int change_num_to_use;
    int want_daylight;

    if (tt == NULL)
      return 0;

    if (is_daylight)
      *is_daylight = 0;

    /* For local times and UTC return 0. */
    if (zone == NULL || zone == &utc_timezone)
      return 0;

    /* Use the builtin icaltimezone if possible. */
    if (zone->builtin_timezone)
      zone = zone->builtin_timezone;

    /* Make sure the changes array is expanded up to the given time. */
    icaltimezone_ensure_coverage (zone, tt->year);

    if (!zone->changes || zone->changes->num_elements == 0)
      return 0;

    /* Copy the time parts of the icaltimetype to an icaltimezonechange so we
       can use our comparison function on it. */
    tt_change.year   = tt->year;
    tt_change.month  = tt->month;
    tt_change.day    = tt->day;
    tt_change.hour   = tt->hour;
    tt_change.minute = tt->minute;
    tt_change.second = tt->second;

    /* This should find a change close to the time, either the change before
       it or the change after it. */
    change_num = icaltimezone_find_nearby_change (zone, &tt_change);

    /* Sanity check. */
    icalerror_assert (change_num >= 0,
                  "Negative timezone change index");
    icalerror_assert (change_num < zone->changes->num_elements,
                  "Timezone change index out of bounds");

    /* Now move backwards or forwards to find the timezone change that applies
       to tt. It should only have to do 1 or 2 steps. */
    zone_change = icalarray_element_at (zone->changes, change_num);
    step = 1;
    change_num_to_use = -1;
    for (;;) {
      /* Copy the change, so we can adjust it. */
      tmp_change = *zone_change;

      /* If the clock is going backward, check if it is in the region of time
         that is used twice. If it is, use the change with the daylight
         setting which matches tt, or use standard if we don't know. */
      if (tmp_change.utc_offset < tmp_change.prev_utc_offset) {
          /* If the time change is at 2:00AM local time and the clock is
             going back to 1:00AM we adjust the change to 1:00AM. We may
             have the wrong change but we'll figure that out later. */
          icaltimezone_adjust_change (&tmp_change, 0, 0, 0,
      } else {
          icaltimezone_adjust_change (&tmp_change, 0, 0, 0,

      cmp = icaltimezone_compare_change_fn (&tt_change, &tmp_change);

      /* If the given time is on or after this change, then this change may
         apply, but we continue as a later change may be the right one.
         If the given time is before this change, then if we have already
         found a change which applies we can use that, else we need to step
         backwards. */
      if (cmp >= 0)
          change_num_to_use = change_num;
          step = -1;

      /* If we are stepping backwards through the changes and we have found
         a change that applies, then we know this is the change to use so
         we exit the loop. */
      if (step == -1 && change_num_to_use != -1)

      change_num += step;

      /* If we go past the start of the changes array, then we have no data
         for this time so we return a UTC offset of 0. */
      if (change_num < 0)
          return 0;

      if ((unsigned int)change_num >= zone->changes->num_elements)

      zone_change = icalarray_element_at (zone->changes, change_num);

    /* If we didn't find a change to use, then we have a bug! */
    icalerror_assert (change_num_to_use != -1,
                  "No applicable timezone change found");

    /* Now we just need to check if the time is in the overlapped region of
       time when clocks go back. */
    zone_change = icalarray_element_at (zone->changes, change_num_to_use);

    utc_offset_change = zone_change->utc_offset - zone_change->prev_utc_offset;
    if (utc_offset_change < 0 && change_num_to_use > 0) {
      tmp_change = *zone_change;
      icaltimezone_adjust_change (&tmp_change, 0, 0, 0,

      if (icaltimezone_compare_change_fn (&tt_change, &tmp_change) < 0) {
          /* The time is in the overlapped region, so we may need to use
             either the current zone_change or the previous one. If the
             time has the is_daylight field set we use the matching change,
             else we use the change with standard time. */
          prev_zone_change = icalarray_element_at (zone->changes,
                                         change_num_to_use - 1);

          /* I was going to add an is_daylight flag to struct icaltimetype,
             but iCalendar doesn't let us distinguish between standard and
             daylight time anyway, so there's no point. So we just use the
             standard time instead. */
          want_daylight = (tt->is_daylight == 1) ? 1 : 0;

#if 0
          if (zone_change->is_daylight == prev_zone_change->is_daylight)
            printf (" **** Same is_daylight setting\n");

          if (zone_change->is_daylight != want_daylight
            && prev_zone_change->is_daylight == want_daylight)
            zone_change = prev_zone_change;

    /* Now we know exactly which timezone change applies to the time, so
       we can return the UTC offset and whether it is a daylight time. */
    if (is_daylight)
      *is_daylight = zone_change->is_daylight;
    return zone_change->utc_offset;

Generated by  Doxygen 1.6.0   Back to index