How to deal with local/UTC DateTime conversion in Kendo MVC Grid? - javascript

I'm getting mad with the Kendo grid. In my ASP.NET MVC project I use a database that contains archive values with a UTC datetime. I want to show these values on my page, but I need the datetime values to be shown as local (browser context) datetime. I also do have two JQuery datepickers for the start/end datetime selection of the desired range that must also work with local time. These two datepickers modify the filters of the grid on each change.
I already managed to change the filter's datetime to UTC by using this code when the datepicker's values change:
var filterExists = false;
$.each($filter, function (index, entry) {
if (entry.field == "DateValue" && entry.operator == "lte") {
entry.value = EndDate.toISOString();
filterExists = true;
console.log("UTCEndDate: " + EndDate.toISOString());
}
})
if (filterExists == false) {
$filter.push({ field: "DateValue", operator: "lte", value: EndDate.toISOString() });
}
When I look into the POST request, the start and end datetimes get send as UTC.
Now the controller fetches the data from the DB like this:
public ActionResult JournalData([DataSourceRequest]DataSourceRequest request)
{
JsonResult jsonNetResult = new JsonResult { JsonRequestBehavior = JsonRequestBehavior.AllowGet };
var JournalData = db.DoubleDataValueArchive.ToDataSourceResult(request, x => new JournalEventModel
{
DateValue = x.DateValue,
StationId = x.StationId,
Value = x.Value,
});
jsonNetResult.Data = JournalData;
return jsonNetResult;
}
Using this code, the data gets returned to the grid in UTC. The data is shown in the grid, but the datetimes don't match the values in the datepickers (which show the local datetime).
As I could not figure out a way to convert these datetimes to local time in the grid itself, I tried converting it to local time in the controller by using
DateValue = x.DateValue.ToLocalTime(),
in the code shown before. But now the grid's datetime filter values don't match. Now, when I want to show data for e.g. the last two hours, the most recent hour is not shown when the client's time is UTC+1. This is extremely annoying and I don't know how to resolve this issue.
As far as I can see, sending and returning datetimes to and from the server in UTC would be the most stable way. All conversion should be done on client side and not on the server. It seems that the grid can not work with UTC "under the hood" and display local time whereever it gets rendered on the page.
I hope that somebody ran into this issue before. Thanks for your help!

Related

Datetime seems to break Google Apps Script client-side deserialization

I've uncovered an odd bug with Google Apps Script's web interface that it can't seem to transport datetime values from the server side to the client.
// Code.gs
function fetchData(){
var spreadsheet = SpreadsheetApp.openByUrl(SHEET_URL)
var sheet = spreadsheet.getSheetByName("My sheet")
var values = sheet.getDataRange().getValues()
Logger.log(values)
return values
}
// javascript.html
<script>
$(function() {
google.script.run.withSuccessHandler(console.log).fetchData()
})
</script>
If I run the above without any dates in the "My sheet" spreadsheet, it works as expected, with the server side Logger.log and the client side console.log showing the same data. But if I input a date type value into the spreadsheet, the Logger.log will still show everything as expected, but the console.log will simply log null.
I checked the XHR and it appears that the data is in fact making it to the browser, but it looks like something about the de-serialization is breaking. If the date is listed as 7/7/21 in the spreadsheet, it is coming across as Wed Jul 07 00:00:00 PDT 2021 in the XHR.
Any ideas about how to fix are much appreciated! Thank you!
You are describing the documented behavior of google.script.run:
Requests fail if you attempt to pass a Date, Function, DOM element besides a form, or other prohibited type, including prohibited types inside objects or arrays. Objects that create circular references will also fail, and undefined fields within arrays become null.
See the reference given by #Cooper.
To pass datetime values between the client and the server, serialize before sending them across. The easiest way is usually to use date.getTime() and pass as integer. Try this:
const values = sheet.getDataRange().getValues().map(value => {
(Object.prototype.toString.call(value) === '[object Date]')
? value.getTime()
: value
});
On the receiving side, use const date = new Date().setTime(value) to convert the integer back to a Date object.
If you do not know the locations of dates in the spreadsheet, but need to detect them in data, you may want to use a magic prefix like 'date:' + value.getTime().

How could Datatime form send epoch format instead of formated date?

I would like to send epoch format value of user datetime selection when the form is been submitted
Would you please tell me how i do that ?
http://s529471052.onlinehome.fr/datetimeform/gpio/test5.htm
I expect to send epoch data with GET method like this : /test5.htm?datetime=1494335700
at the moment it sends outstanding format what would not be usuable in backend :
/test5.htm?datetime=29+December+2016+-+10%3A50&submit=
--
By the way, for some unknown reasons 'Delete' and 'Calendar' graphicon icons won't be displayed in the datetimeform even css file is there.
Since the 'DateTimePicker' library you're using doesn't seem to have any support for this, you'll have to patch it yourself.
Firstly give the existing #dtp_input1 element a name so that it will be sent as a parameter:
<input id="dtp_input1" name="dtp_input1" type="hidden"/>
Next we need to hook the picker's setValue() method in order to put the field's value into the format we want:
/* get the datetimepicker controller */
let picker = $(`.form_datetime`).data(`datetimepicker`);
/* override its setValue() method */
let f = picker.setValue;
picker.setValue = function(...xs) {
/* call the original method first */
f.call(this, ...xs);
/* now set the linked field to epoch format */
$(`#${this.linkField}`)
.val(`${(this.getDate() || new Date(0)).getTime()}`);
};
Now when you submit the form it should yield a query something like this:
?datetime=20+January+2017+-+03%3A15&dtp_input1=1484842500000
where dtp_input1 is the epoch value and datetime is the human-readable string from the text box.

ColumnMapping.DataTableToObjectList gives me DateTime properties lacking timezone information

I have a webapi function that retrieves data from a T-SQL database using SqlConnection, SqlCommand etc. I get a DataTable which I convert to a data structure using
var foobars = ColumnMapping.DataTableToObjectList<Foobar>(dt)
The Foobar class contains DateTime fields.
When I return my foobars from the webapi method, those datetimes will be sent over the network in the following format:
2016-10-12T12:00:00
which seems to be a timezone-less datetime. AngularJS will treat it as 12:00, and javascript´s Date.getHours() will return 14 (I am in the +2 timezone).
If I do this operation before I return from my Web api method:
foobar.d = foobar.d.ToUniversalTime();
the string will get an additional Z
2016-10-12T12:00:00Z
and both AngularJS and javascript will agree about which time that is (12:00, which is also the indended time).
If I do
foobar.d = foobar.d.DateStart.ToLocalTime();
the string will be
2016-10-12T14:00:00+02:00
and AngularJS and javascript both reports it is 14:00, two hours more than the intended time).
From this, I conclude that
A DateTime object can be timezoneless, but if you try to convert it, it will be treated as if it was UTC.
ColumnMapping.DataTableToObjectList creates structures where DateTime objects are timezoneless.
I do not want to "patch" every DateTime object, that would be an error source (that would involve calling ToUniversalTime() on every DateTime object).
Can I specify a locale when I call ColumnMapping.DataTableToObjectList?
In webapi you can configure your JsonFormatter to serialize your datetimes how you want:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
}
}
This way you don't have to do it for every datetime, assuming I'm understanding your issue...

Ignoring time zone in date object returned from an API using Angular

I'm getting a response from an API containing a date in the following format "/Date(1447773909000-0500)/"
I have an angular filter that pulls out the timestamp:
.filter('formattedDate', function () {
return function (posteddate) {
if (!posteddate || !posteddate.length) {
return;
}
return posteddate.slice(6, 19);
};
})
When I display the date I use two filters, mine and the angular date filter to properly format it.
<span class="list-content col-sm-6">{{appointment.ApptDateTime | formattedDate | date:'MMM dd, yyyy hh:mm a'}}</span>
The problem I'm having is the time is adjusting based off the users current time zone. I want to ignore this and instead use the value as it's returned with out altering it. I notice that depending on the timezone of the computer the response from the API changes the returned date. So instead of "/Date(1447773909000-0500)/" it will respond with "/Date(1447914211000-0700)/"
Try adding following line in your WebApiConfig file.
config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling
= Newtonsoft.Json.DateTimeZoneHandling.Local;

OData Date Filtering from JS

I am using the DXTREME framework from Devexpress to connect a HTML mobile app to an OData source.
One of my tables in SQL Server, exposed through the OData service is a table with a date (not datetime) field in it. It is exposed through OData like this:
<d:TaskDate m:type="Edm.DateTime">2010-04-01T00:00:00</d:TaskDate>
I am trying to filter the data on this field through a calendar control, but when I try to filter the datasource on the JS side, I get no matches. This is because the date is passed to the OData service, I believe, in UTC format, so if I query for TaskDate = '10/JUL/2013', I believe the date is passed as "09/JUL/2013 14:00". If I filter on TaskDate > '10/JUL/2013' I get results back from after "09/JUL/2013 14:00" at any rate.
I have tried declaring a new date with no time part:
filterDate = new Date(2013, 6, 10)
but is still doesn't work, it still subtracts 10 formy time zone on the JS side.
What I want to do is to return a lists of Tasks valid on that particular date. How can I achieve this?
I think my problem was the confusion around the dxDateBox control returning just a date, and that date being changed when passed to my odata service.
I solved the issue by converting the date to UTC myself, but just using the Date parts from the control, (where filterDate came from the control):
var paramDate = new Date(Date.UTC(this.filterDate().getFullYear(), this.filterDate().getMonth(), this.filterDate().getDate()));
this.dataSource.filter(["TaskDate", "=", paramDate]);
This works nicely, but seems rather verbose.

Categories

Resources