Microsoft Graph API and events start and end dates - timezone

I am working with the Graph API and trying to create events using the C# Microsoft.Graph API. Let's assume to have the following Microsoft.Graph.Event objects:
{
Subject = "A Title",
Body = new ItemBody(),
Start = {
DateTime = "2022-10-24T00:00:00",
TimeZone = "W. Europe Standard Time"
},
End ={
DateTime = "2022-10-25T00:00:00",
TimeZone = "W. Europe Standard Time"
},
IsAllDay = true,
},{
Subject = "B Title",
Body = new ItemBody(),
Start = new DateTimeTimeZone {
DateTime = "2022-10-28T13:30:00",
TimeZone = "W. Europe Standard Time"
},
End = new DateTimeTimeZone {
DateTime = "2022-10-28T16:45:00",
TimeZone = "W. Europe Standard Time"
},
IsAllDay = false,
}
They are successfully written into my calendar trough twice call to:
await _graphServiceClient.Users[emailAddress].Events.Request().AddAsync(graphEvent);
and I see:
and
which is the expected behaviour.
Querying the API with the filter "start/dateTime ge '2022-10-24T00:00:00'" I get just B Title, A Title is missing. Furthermore the start and end dates are wrong, I get 2022-10-28T11:30:00.0000000 and 2022-10-28T14:45:00.0000000.
If I edit the query to "start/dateTime ge '2022-10-23T00:00:00'" I get both, the dates of B title are the same (wrong), but the ones of A Title ar correct 2022-10-24T00:00:00.0000000 and 2022-10-25T00:00:00.0000000.
I expected that B Title has 2022-10-28T13:30:00.0000000 and 2022-10-28T16:45:00.0000000. What am I doing wrong?

When you call list events endpoint you can specify request header Prefer: outlook.timezone="<time-zone>". If not specified, those time values are returned in UTC.
Example:
var events = await _graphServiceClient.Users[emailAddress]
.Events
.Request()
.Header("Prefer","outlook.timezone=\"W. Europe Standard Time\"")
.GetAsync();
I guess that with the correct outlook.timezone header your query will return also A Title and correct time values.
References:
Calendar list events - request headers

Related

Cannot get a single calendar event

I'm having trouble reading a single calendar event, calling:
Api::get('me/calendar/'.$id);
(API:: is a wrapper for Guzzle)
returns the errors:
The specified object was not found in the store.
I know it's a valid id as I've listed my calendar events:
$records = Api::get("me/calendarview?startdatetime=$start&enddatetime=$end&\$top=1000");
foreach ($records['value'] as $row) {
$events[] = array(
'id' => $row['id'],
'title' => $row['subject'],
'start' => date("Y-m-d H:i:s", strtotime($row['start']['dateTime'])),
'end' => date("Y-m-d H:i:s", strtotime($row['end']['dateTime'])),
'allDay' => $row['isAllDay'],
);
}
return $events;
The output contains the id:
{
"id": "AAMkADdlZTBjNjQ4LWI0OGItNDFhZS05ZDNiLThiY2JkYzIzZWZkYwBGAAAAAABFX7lJCx7ZRLTJ6iI0yZK6BwC8b_tAO4nLRZCbkhud5CXFAAAAAAEOAAC8b_tAO4nLRZCbkhud5CXFAAMc9p8aAAA=",
"title": "TOP - DC/JB - FEO",
"start": "2017-11-27 15:00:00",
"end": "2017-11-27 16:30:00",
"allDay": false
}
I've then used that id and attempted to return a single entry, the same happens when I use the Graph Explorer so I'm wondering if there is a bug or the documentation is incorrect.
The endpoint for fetching a single calendar entry is /me/events/{id}, not /me/calendar/{id}:
Api::get('me/events/'.$id);
The /calendar endpoint returns a Calendar resource whereas you're looking for an Event resource (a child object of the Calendar)

SDN5/OGM3 compare java.util.Date at Cypher query

I have the following entity:
#NodeEntity
public class Action {
...
#Index(unique = false)
private Date createDate;
...
}
I need to get the last Action that was created during some previous period of time.
In order to do this I have implemented the following repository method:
#Repository
public interface ActionRepository {
#Query("MATCH (a:Action)-[:CREATED_BY]->(u:User) WHERE a.entityType = {entityType} AND a.createDate <= {minCreateDate} AND u.id = {userId} RETURN a ORDER BY a.createDate DESC LIMIT 1")
Action findLastByEntityTypeForUser(#Param("entityType") String entityType, #Param("minCreateDate") Date minCreateDate, #Param("userId") Long userId);
}
I use the following code to test this method:
decisionDao.create("Decision2", "Decision2 description", null, false, null, user1);
Date minStartDate = DateUtils.addMilliseconds(new Date(), -1000 * 60);
Action user1LastAction = actionRepository.findLastByEntityTypeForUser(Decision.class.getSimpleName(), minStartDate, user1.getId());
assertNotNull(user1LastAction); // test fails here because of NPE
but without this part of the Cypher query AND a.createDate <= {minCreateDate} I can successfully find Action instance.
At Neo4j level my data looks like:
{
"updateDate":"2017-10-08T12:21:39.15
3Z",
"entityName":"General",
"en
tityType":"CriterionGroup",
"entityId":1,
"id":1,
"type":"CREATE",
"createDate":"2017-10-08T12:21:39.153Z"
}
What am I doing wrong and how to properly compare the dates with SDN/OGM and Cypher?
Also, is there any way to tell SDN/OGM to store java.util.Date object as long milliseconds and as String?
the minCreateDate parameter you use for your find-Method is of type Date and the createDate property is a String. So, this part a.createDate <= {minCreateDate} is basically comparing the String representation of minCreateDate and the String property createDate.
In my projects, I usually save the dates and timestamps as long both in the database and in my code.
Or even better, if the date attributes are crucial for my application, I'm using the "Time Tree Model" approach: https://graphaware.com/neo4j/2014/08/20/graphaware-neo4j-timetree.html

How to filter DateTime data using sap.ui.model.Filter?

I've tried to filter DateTime data using sap.ui.model.Filter:
oTableSearchState = [new Filter([
new Filter("Date", FilterOperator.Contains, sQuery),
new Filter("Another_Date", FilterOperator.Contains, sQuery),
])]
it return 400 Bad String. I found that the odata request is ...$filter substringof(,Date). So I know it's not correct that using a "string filter" to filter date.
what I need is ...$filter= Date ge datetime'2016-08-17T16:00:00Z' and Date lt datetime'2016-08-18T16:00:00' Can I do that with sap.ui.model.Filter? Or the only way to do that is put filter parameters together by my own hands?
Yes you can, please use sap.ui.model.Fitler as (using operator BT):
new sap.ui.model.Filter("Date", sap.ui.model.FilterOperator.BT, dateFrom, dateTo)
Selection of dates can be done by handling sap.m.DateRangeSelection event "change"
handleChange : function(oEvent){
dateFrom = oEvent.getParameter("from");
dateTo = oEvent.getParameter("to");
}

Ember.js Query Parameters - Update query results when creating a model

I am using the new query-params in Ember.js to filter entries by date. I have added a field to add new entries, with the date being automatically assigned as the query date. When a new entry is added it only shows up on the page when I refresh. Is there any way to retrigger the query without changing the query itself?
Controller: (simplified)
queryParams: 'date'
date: null
filteredEntries: ( ->
date = #get('date')
model = #get('model')
if (date)
return entries.filterProperty('date', date)
else
return entries
).property('date', 'model')
actions:
createEntry: ->
entry = #store.createRecord('entry', { date: #get('date') })
entry.save()
I also tried this, but it didn't work:
entry.save().then -> this.transitionTo({queryParams: { date: #get('date')}})
I think this is what you are looking for (in your route):
App.MyRoute = Ember.Route.extend({
queryParams: {
date: {
refreshModel: true
}
},
});
This will refresh your model everytime the value of date changes.

Trouble using Url.Action() when trying to create friendly & "hackable" urls

I've defined the following route for a simple blog.
routes.MapRoute(
"Blog",
"blog/{year}/{month}/{day}",
new { controller = "Blog", action = "Index" },
new { year = #"\d{4}", month = #"\d{2}", day = #"\d{2}" }
);
The url should be able "hackable" to accomplish the following:
http://abc.com/blog/2010 -> shows all
posts in 2010
http://abc.com/blog/2010/01 -> shows
all posts in January 2010
http://abc.com/blog/2010/01/25 ->
shows all posts in January 25th, 2010
I have created a controller which handles this action quite nicely. However I am having trouble creating links in my views using Url.Action().
For example this...
var d = new DateTime(2010, 1, 25);
Url.Action("Index", "Blog", new { year=d.Year, month=d.Month, day=d.Day} );
...generates a url like that looks like this:
http://abc.com/blog?year=2010&month=2&day=21
I would rather like it to generate a url that looks like the urls in the list above.
http://abc.com/blog/2010/02/21
Is there any way I can use Url.Action() or Html.ActionLink() to generate urls in the format I desire?
The issue there is that the month you're passing in to Url.Action is a single-digit month, and thus doesn't match the month constraint on the route definition. Constraints are typically run not only on incoming URLs but also when generating URLs.
The fix would be to manually call .ToString() on the month and format it as a two-digit number. You'll need to do the same for the day as well. For the year it's not an issue since all the years in our lifetimes will be four-digit numbers.
Here's sample code to format numbers:
int month = 2;
string formattedMonth = month.ToString("00", CultureInfo.InvariantCulture);
// formattedMonth == "02"
Please note that when formatting the number manually that you must use the Invariant Culture so that different cultures and languages won't affect how it gets formatted.
You'll also need to set default values for month and day so that they are not required in the URL:
routes.MapRoute(
"Blog",
"blog/{year}/{month}/{day}",
new { controller = "Blog", action = "Index", month = "00", day = "00" },
new { year = #"\d{4}", month = #"\d{2}", day = #"\d{2}" }
);
And in your controller action check if the month or day are 0, in which case you should show an entire month or entire year.
The other issue I see you running into is that you'll need several other route entries with appropriate defaults to handle those other scenarios.
"http://abc.com/2010" will not match "blog/{year}/{month}/{day}". That's a very specific route that requires three parameters (with constraints) to match. In order to accept those other routes you'll need to create other route entries along the lines of:
routes.MapRoute(
null,
"blog",
new { controller = "Blog", action = "Index", year = 0000, month = 00, day = 00 },
new { year = #"\d{4}", month = #"\d{2}", day = #"\d{2}" }
);
routes.MapRoute(
null,
"blog/{year}",
new { controller = "Blog", action = "Index", month = 00, day = 00 },
new { year = #"\d{4}" }
);
routes.MapRoute(
null,
"blog/{year}/{month}",
new { controller = "Blog", action = "Index", day = 00 },
new { year = #"\d{4}", month = #"\d{2}"}
);
There are a few ways to handle this scenario, but now in your Blog controller and your Index action you can filter the posts results by year, month, day.
Quick example:
if(year == 0000 && month == 00 && day == 00)
var posts = postsRepository.GetAllPost();
else if(year != 0000 && month == 00 && day == 00)
var posts = postsRepository.GetPostsByYear(year);
...
You dont have to write new method for all condition. I mean you can do it with this;
eg. for NHibernate.
public IList<Blog> GetBlogs(int? day, int? month, int? year) {
IQueryable<Blog> iQBlog = Session.Linq<Blog>();
if (year.HasValue) {
iQBlog = iQBlog.Where(b => b.Year == year);
if (month.HasValue) {
iQBlog = iQBlog.Where(b => b.Month == month);
if (day.HasValue) {
iQBlog = iQBlog.Where(b => b.Day == day);
}
}
}
return iQBlog.ToList();
}
ps. It's checking parameters step by step, year -> month -> day. If user doesnt set any parameters in querystring, it will return all blogs.

Resources