This is a migrated thread and some comments may be shown as answers.

Time Zone On Appointment

2 Answers 132 Views
Scheduler
This is a migrated thread and some comments may be shown as answers.
Michael
Top achievements
Rank 1
Michael asked on 25 Jul 2018, 03:51 PM

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 Answers, 1 is accepted

Sort by
0
Michael
Top achievements
Rank 1
answered on 25 Jul 2018, 08:15 PM
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.
0
Peter Milchev
Telerik team
answered on 30 Jul 2018, 02:05 PM
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.
Tags
Scheduler
Asked by
Michael
Top achievements
Rank 1
Answers by
Michael
Top achievements
Rank 1
Peter Milchev
Telerik team
Share this question
or