Time Zone On Appointment

3 posts, 0 answers
  1. Michael
    Michael avatar
    23 posts
    Member since:
    Sep 2014

    Posted 25 Jul 2018 Link to this post

    I am in the process of adding Time Zone functionality into our existing Scheduler which did not include it.  I am having an issue when I set a TimeZoneId on the Scheduler and then use the Advanced Form with EnableTimeZonesEditing turned on.  The times of the appointment that get stored in UTC reflect the time zone of the Scheduler, not for the appointment.  For example, if I set the TimeZoneId of the Scheduler to "Pacific Standard Time" and add an appointment for July 25, from 1:00 PM to 2:00 PM with a timezone of "Eastern Standard Time", I would expect the stored time of the appointment to be 17:00 to 18:00 UTC.  However, when I view the appointment in the AppointmentInsert event, the start time is 20:00 UTC and then end time is 21:00 UTC, even though the TimeZoneId of the appointment shows as "Eastern Standard Time".

    Am I supposed to do the calculation myself when adding an appointment with a different timezone than the Scheduler, or should this be done automatically?  Looking at the code for the Time Zones demo for the Scheduler, I don't see any additional code for this calculation, yet it seems to work as expected.

  2. Michael
    Michael avatar
    23 posts
    Member since:
    Sep 2014

    Posted 25 Jul 2018 Link to this post

    I am using the Advanced Form with the Advanced Template User Controls as illustrated here for inserting and editing appointments, which seems to be the issue.  It looks like that control doesn't make any adjustment to the start and end time to account for the difference in time zone between the calendar and the appointment, it just calculates the times based off of the time zone of the calendar, ignoring the appointment.  So I guess I'll have to account for this myself and update the times accordingly.
  3. Peter Milchev
    Admin
    Peter Milchev avatar
    532 posts

    Posted 30 Jul 2018 Link to this post

    Hello Michael,

    You are correct, the provided examples of the Advanced Form do not handle the appointment timezones correctly. The handling of that should be done in the Start and End properties.

    Following is a sample implementation that takes the timezone into account and is based on the demo in the https://www.telerik.com/support/code-library/custom-advanced-form-with-required-resources CodeLibrary project: the Start and End properties should be improved as follows and the HasTimeZoneOffset, GetTimeZoneModelById, LocalToUtc and UtcToLocal methods should be implemented. 

    [Bindable(BindableSupport.Yes, BindingDirection.TwoWay)]
    public DateTime Start
    {
        get
        {
            DateTime result = StartDate.SelectedDate.Value.Date;
     
            if (AllDayEvent.Checked)
            {
                result = result.Date;
            }
            else
            {
                TimeSpan time = StartTime.SelectedDate.Value.TimeOfDay;
                result = result.Add(time);
            }
     
            if (HasTimeZoneOffset)
            {
                return Owner.DisplayToUtc(result);
            }
     
            return LocalToUtc(result, GetTimeZoneModelById(TimeZoneID));
        }
     
        set
        {
            if (HasTimeZoneOffset)
            {
                StartDate.SelectedDate = Owner.UtcToDisplay(value);
                StartTime.SelectedDate = Owner.UtcToDisplay(value);
            }
            else
            {
                StartDate.SelectedDate = UtcToLocal(value, GetTimeZoneModelById(Appointment.TimeZoneID));
                StartTime.SelectedDate = UtcToLocal(value, GetTimeZoneModelById(Appointment.TimeZoneID));
            }
        }
    }
     
    [Bindable(BindableSupport.Yes, BindingDirection.TwoWay)]
    public DateTime End
    {
        get
        {
            DateTime result = EndDate.SelectedDate.Value.Date;
                 
            if (AllDayEvent.Checked)
            {
                result = result.Date.AddDays(1);
            }
            else
            {
                TimeSpan time = EndTime.SelectedDate.Value.TimeOfDay;
                result = result.Add(time);
            }
     
            if (HasTimeZoneOffset)
            {
                return Owner.DisplayToUtc(result);
            }
     
            return LocalToUtc(result, GetTimeZoneModelById(TimeZoneID));
        }
     
        set
        {
            if (HasTimeZoneOffset)
            {
                EndDate.SelectedDate = Owner.UtcToDisplay(value);
                EndTime.SelectedDate = Owner.UtcToDisplay(value);
            }
            else
            {
                EndDate.SelectedDate = UtcToLocal(value, GetTimeZoneModelById(Appointment.TimeZoneID));
                EndTime.SelectedDate = UtcToLocal(value, GetTimeZoneModelById(Appointment.TimeZoneID));
            }
        }
    }
    protected bool HasTimeZoneOffset
    {
        get
        {
            return !Owner.TimeZonesEnabled && Owner.TimeZoneOffset != TimeSpan.Zero;
        }
    }
     
    public TimeZoneInfo GetTimeZoneModelById(string id)
    {
        try
        {
            if (string.IsNullOrEmpty(id))
            {
                id = TimeZoneInfo.Utc.Id;
            }
     
            return TimeZoneInfo.GetSystemTimeZones().First<TimeZoneInfo>(timeZoneInfo =>
            {
                return timeZoneInfo.Id == id;
            });
        }
        catch (InvalidOperationException ex)
        {
            throw new TimeZoneNotFoundException("Time Zone with the provided Id was not found", ex);
        }
        catch (Exception ex1)
        {
            throw new TimeZoneNotFoundException("Time Zone with the provided Id was not found", ex1);
        }
    }
     
    public DateTime LocalToUtc(DateTime local, TimeZoneInfo timeZone)
    {
        var offset = timeZone.GetUtcOffset(local);
             
        return new DateTime(local.Add(-offset).Ticks, DateTimeKind.Utc);
    }
     
    public DateTime UtcToLocal(DateTime local, TimeZoneInfo timeZone)
    {
        var offset = timeZone.GetUtcOffset(local);
     
        return new DateTime(local.Add(offset).Ticks, DateTimeKind.Utc);
    }

    Here is also the VB version: 

    <Bindable(BindableSupport.Yes, BindingDirection.TwoWay)>
    Public Property Start() As DateTime
        Get
            Dim result As DateTime = StartDate.SelectedDate.Value.[Date]
            If AllDayEvent.Checked Then
                result = result.[Date]
            Else
                Dim time As TimeSpan = StartTime.SelectedDate.Value.TimeOfDay
                result = result.Add(time)
            End If
      
            If HasTimeZoneOffset Then
                Return Owner.DisplayToUtc(result)
            End If
      
            Return LocalToUtc(result, GetTimeZoneModelById(TimeZoneID))
        End Get
      
        Set(ByVal value As DateTime)
            If HasTimeZoneOffset Then
                StartDate.SelectedDate = Owner.UtcToDisplay(value)
                StartTime.SelectedDate = Owner.UtcToDisplay(value)
            Else
                StartDate.SelectedDate = UtcToLocal(value, GetTimeZoneModelById(Appointment.TimeZoneID))
                StartTime.SelectedDate = UtcToLocal(value, GetTimeZoneModelById(Appointment.TimeZoneID))
            End If
        End Set
    End Property
      
    <Bindable(BindableSupport.Yes, BindingDirection.TwoWay)>
    Public Property [End]() As DateTime
        Get
            Dim result As DateTime = EndDate.SelectedDate.Value.[Date]
            If AllDayEvent.Checked Then
                result = result.[Date].AddDays(1)
            Else
                Dim time As TimeSpan = EndTime.SelectedDate.Value.TimeOfDay
                result = result.Add(time)
            End If
      
            If HasTimeZoneOffset Then
                Return Owner.DisplayToUtc(result)
            End If
      
            Return LocalToUtc(result, GetTimeZoneModelById(TimeZoneID))
        End Get
      
        Set(ByVal value As DateTime)
            If HasTimeZoneOffset Then
                EndDate.SelectedDate = Owner.UtcToDisplay(value)
                EndTime.SelectedDate = Owner.UtcToDisplay(value)
            Else
                EndDate.SelectedDate = UtcToLocal(value, GetTimeZoneModelById(Appointment.TimeZoneID))
                EndTime.SelectedDate = UtcToLocal(value, GetTimeZoneModelById(Appointment.TimeZoneID))
            End If
        End Set
    End Property
      
    Protected ReadOnly Property HasTimeZoneOffset As Boolean
        Get
            Return Not Owner.TimeZonesEnabled AndAlso Owner.TimeZoneOffset <> TimeSpan.Zero
        End Get
    End Property
      
    Public Function GetTimeZoneModelById(ByVal id As String) As TimeZoneInfo
        Try
            If String.IsNullOrEmpty(id) Then
                id = TimeZoneInfo.Utc.Id
            End If
      
            Return TimeZoneInfo.GetSystemTimeZones().First(Function(timeZoneInfo) timeZoneInfo.Id = id)
        Catch ex As InvalidOperationException
            Throw New TimeZoneNotFoundException("Time Zone with the provided Id was not found", ex)
        Catch ex1 As Exception
            Throw New TimeZoneNotFoundException("Time Zone with the provided Id was not found", ex1)
        End Try
    End Function
      
    Public Function LocalToUtc(ByVal local As DateTime, ByVal timeZone As TimeZoneInfo) As DateTime
        Dim offset = timeZone.GetUtcOffset(local)
        Return New DateTime(local.Add(-offset).Ticks, DateTimeKind.Utc)
    End Function
      
    Public Function UtcToLocal(ByVal local As DateTime, ByVal timeZone As TimeZoneInfo) As DateTime
        Dim offset = timeZone.GetUtcOffset(local)
        Return New DateTime(local.Add(offset).Ticks, DateTimeKind.Utc)
    End Function


    Regards,
    Peter Milchev
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
Back to Top