4

I'm using the graph client sdk. Making a call to CalendarView with startDateTime = 2019-11-20T10:00:00.0000000 and endDateTime = 2019-11-20T23:00:00.0000000.

Before I go any further, none of the Events are all day. Many are reoccurring, so this is why I'm not using the Events endpoint, but using CalendarView.

I have the timezone set for the calendar events by setting prefer, outlook.timezone="Eastern Standard Time" -- No problem there. I can see the event start and end times in Eastern Standard Time.

However, the events are not correct. I have an event that starts at 8:00 am EST and one that starts at 6:30 pm EST.

  • The 8:00 am meeting shows--when it should not because my start criteria are 10 am. Not a big deal, but it may be because it ends at 10 am.

  • The 6:30 pm meeting does NOT show and it should because my end time is 11:00 pm. This is a problem.

  • If I move the 6:30 meeting up to 6:00 it shows in the collection.

So I'm thinking since I am UTC -5, the startDateTime is locked in UTC time. It does not go by the header timezone. I know that the header timezone as mentioned above is working, because the actual start/end of my events will show Eastern if I have the header set, and UTC if I do not.

I can't find anything that allows me to force the calendarview?$select=subject,start, end&startDateTime=2019-11-20T10:00:00.0000000&endDateTime=2019-11-20T23:30:00.0000000 to use my local time.

I played around with this in Graph Explorer and found out that I can put -5 after the time, and it appears to work. I still get the 8:00 am event, but I also get my 6:30 event. I don't want to do this in my code because then I'll be forcing other users to use my timezone.

Does anyone know what setting can be changed to force the CalendarView to use local time for the parameters? I apologize, I'm new to graph client so I may not be using the correct vocabulary.

Code:


GraphServiceClient graphClient = new GraphServiceClient(AuthProvider);

DateTime d = DateTime.Now.ToLocalTime();
DateTime.SpecifyKind(d, DateTimeKind.Unspecified).ToString("o");
string MicrosoftDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffff";
var start = d.ToString(MicrosoftDateTimeFormat);
var end = d.ToString("yyyy'-'MM'-'dd'T'23:59:59.0"); //"2019-07-24T23:00:00.0";//

start = "2019-11-20T10:00:00.0000000"; //for debug only
end = "2019-11-20T23:00:00.0000000"; //for debug only

List<Option> options = new List<Option>
{
    new QueryOption("startDateTime", start),
    new QueryOption("endDateTime", end),
    new QueryOption("orderby", "start/dateTime")
};

var events = await graphClient.Me.CalendarView
    .Request(options)
    .Header("Prefer", "outlook.timezone=\"" + TimeZoneInfo.Local.Id + "\"")
    .Select(e => new
    {
        e.Subject,
            e.Body,
            e.BodyPreview,
            e.Organizer,
            e.Attendees,
            e.Start,
            e.End,
            e.Location
    })
    .GetAsync();
Marc LaFleur
  • 31,987
  • 4
  • 37
  • 63
J. Wilson
  • 101
  • 1
  • 7
  • Thank you for the question - I was trying to figure out the same today and these answers helped me. You should mark one of them as "Answer". – Andrey Nov 23 '19 at 03:27
  • You're welcome! I like Marc's answer, but I do want to try his suggestion. I think it would ultimately simplify my code, but I was under a deadline, so I won't be able to try it anytime soon. I think I can later update the answer, but for now, I will mark my answer as the final answer. Glad this helped you! – J. Wilson Nov 24 '19 at 15:07

2 Answers2

4

The prefer: outlook.timezone="Eastern Standard Time" header only affects the API response. Your header will ensure the results are returned in EST but that timezone transformation happens after the results are retrieved. On the backend, every Event is stored as UTC -0.

In order to request events within the bounds of a given timezone, that timezone needs to be encoded into the startTime and endTime values using the ISO 8601 format:

YYYY-MM-DDThh:mm:ss±hh:mm

or more simply put:

{date}T{time}±{offset}

So in order to transform your startDateTime of 2019-11-20T10:00:00.0000000 to Easter Standard it would be 2019-11-20T10:00:00-5.

In C#, the DateTimeOffset object can generate the proper format for you using .ToString("O"):

var tzOffset = new TimeSpan(-5, 0, 0);
var dateTime = new DateTimeOffset(2019, 11, 20, 10, 0, 0, tzOffset);

List<Option> options = new List<Option>
{
    new QueryOption("startDateTime", dateTime.ToString("O")),
    new QueryOption("endDateTime", dateTime.AddHours(24).ToString("O"))
};

You can also lookup the correct UTC offset for a given Time Zone using the TimeZoneInfo class. This is generally a good idea since Time Zones change far more frequently than you'd imagine:

TimeSpan tzOffset = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time").BaseUtcOffset;
DateTimeOffset dateTime = new DateTimeOffset(2019, 11, 20, 10, 0, 0, tzOffset);

List<Option> options = new List<Option>
{
    new QueryOption("startDateTime", dateTime.ToString("O")),
    new QueryOption("endDateTime", dateTime.AddHours(24).ToString("O"))
};
Marc LaFleur
  • 31,987
  • 4
  • 37
  • 63
  • 2
    Thank you @MarcLaFleur! This is very helpful. I wasn't able to try it because I had a deadline, but I think this would end up simplifying my code, because later down in my method, I'm doing other things to verify that the date is the current date in local time. I'm almost positive your suggestions would help me eliminate that and deal with the time span one time. When I get back from vacation, I'll try this and update the post to mark yours as the answer--I think I can later do that. Thanks again!! – J. Wilson Nov 24 '19 at 15:10
1

Okay, so I got it working. This answer was very helpful. The answer showed up in related questions when I checked in this morning.

As they say, when in Rome...so in my case, when in UTC do as the UTC'ans. So I'm just keeping everything in UTC time. I did conclude that the DateTime (start and end) for the CalendarView request is in UTC time, with apparently no way to change it. So I just leave my current timestamp in UTC. I only change the time to local when I display the event start/end times in my UI. Made a big deal out of nothing! Haha.

Note: It still kept my 8am meeting, but again, that's not a killer. I wish I new why, but that's for another day.

In case this can help another kinda-newbie like me here's my final code segment:

 GraphServiceClient graphClient = new GraphServiceClient(AuthProvider);

        DateTime d = DateTime.UtcNow; //DateTime.Now.ToLocalTime();
        //d = DateTime.Parse("11/20/2019 08:14:34 PM"); //for debug only

        DateTime.SpecifyKind(d, DateTimeKind.Unspecified).ToString("o");
        string MicrosoftDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffff";
        var start = d.ToString(MicrosoftDateTimeFormat);
        var end = d.ToString("yyyy'-'MM'-'dd'T'23:59:59.9");            //"2019-07-24T23:00:00.0";//

        //start = "2019-11-20T10:00:00.0000000"; //for debug only
        //end = "2019-11-20T23:59:59.0000000";   //for debug only
        //var link = $"https://graph.microsoft.com/v1.0/me/calendarview?startdatetime={start}&enddatetime={end}&orderby=start/dateTime";  //not used. was previously used for http call; before moving to sdk.
        List<Option> options = new List<Option>
        {
            new QueryOption("startDateTime", start),
            new QueryOption("endDateTime", end),
            new QueryOption("orderby", "start/dateTime")
        };

        var events = await graphClient.Me.CalendarView
        .Request(options)
        //.Header("Prefer", "outlook.timezone=\"" + TimeZoneInfo.Local.Id + "\"")            
        .Select(e => new
        {
            e.Subject,
            e.Body,
            e.BodyPreview,
            e.Organizer,
            e.Attendees,
            e.Start,
            e.End,
            e.Location
        })            
        .GetAsync();
J. Wilson
  • 101
  • 1
  • 7