Hello, how can I set the DateTimeZoneHandling to Local in new .net5 projects?
Moreover I get documentation about Newtonsoft, but I think default serializer are ext.
When I post a DateField value I get zulu time and date changes.
Thank you!!
Printable View
Hello, how can I set the DateTimeZoneHandling to Local in new .net5 projects?
Moreover I get documentation about Newtonsoft, but I think default serializer are ext.
When I post a DateField value I get zulu time and date changes.
Thank you!!
Hello @bbros!
I'm not sure how you're handling it, could you provide a test case that illustrates the unexpected time zone behavior?
There may be an issue related to that due to a breaking change Sencha introduced with client-side serialization around late 4.x and 5.x versions that could affect your scenario but we'd only be able to help you if we know we are on the same page.
Looking forward to your follow-up!
Sure!
here is the repro project:
DateTimeZoneHandling.cshtml
DateTimeZoneHandling.cshtml.csCode:@page
@model ExtCookbook.Pages.DateTimeZoneHandlingModel
@{
}
<ext-section target="Main">
<ext-container region="Center" scrollable="true" paddingAsString="30 20 30 50">
<content>
<h1>DateField</h1>
<ext-container id="MainContainer" model="Model.MainContainer">
</ext-container>
</content>
</ext-container>
</ext-section>
and the result, here in Italy where we are GMT+2, is this:Code:using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Ext.Net;
using Ext.Net.Core;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace ExtCookbook.Pages
{
public class DateTimeZoneHandlingModel : PageModel
{
public FieldContainer MainContainer { get; set; }
public void OnGet()
{
MainContainer = new FieldContainer()
{
Anchor = "100%"
};
MainContainer.Items.Add(new DateField()
{
Id="myDateField"
});
var btn = new Button()
{
Text = "Click me"
};
btn.DirectEvents.Click.Method = HttpMethod.POST;
btn.DirectEvents.Click.Url = $"?handler=ClickMeButtonClick";
btn.DirectEvents.Click.ExtraParams.Add(new DirectEventParameter() { Key = "myDate", Value = "App.myDateField.value", Mode = ParameterMode.Raw });
MainContainer.Items.Add(btn);
}
public IActionResult OnPostClickMeButtonClick(JsObject jObj)
{
string postedValue = jObj.GetValueOrDefault("myDate").Value.ToString();
this.X().Toast(postedValue);
return this.Direct();
}
}
}
Attachment 25554
Converting to local time serverside I get what I need, anyhow it is confusing.
TimeField as well returns a DateTime instead of TimeSpan, and it's date part is 2008-01-01 which could have a different daylight saving time.
Code:var date = DateTime.Parse(postedValue, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal);
Hello @bbros!
Thanks for the test case and also for sharing the solution you went with so far.
Your solution will work just fine for you, if you can ensure everyone will be in the same time zone of your server, or if you do extra math to infer the time zone the clients are in, and calculate the "UTC skew" or something like it. But no matter how we look at it, it really sounds complicated and error-prone, don't you agree?
So what if we could pass just what we see in the field?
I have changed line 32 from your model code to this:
So that we send the date that is filled and displayed in the field, instead of letting client browsers go awol with their complex and perhaps mostly unnecessary time zone and skew calculus and give the server hard times. I've seen some discussions on browsers handling differently different time zones so my advice is, whenever you can avoid letting the browser handle it for you, do avoid it.Code:btn.DirectEvents.Click.ExtraParams.Add(new DirectEventParameter() { Key = "myDate", Value = "App.myDateField.getRawValue()", Mode = ParameterMode.Raw });
And in fact, as I pointed in our last post, a change from Sencha's ExtJS (Ext.NET's underlying framework), from late Ext.NET 4.x, induced a bit more "browser date handling" while serializing data to the server. But as per your test case, it was fortunately not the case and you already got full control on what you're sending, so it's a good scenario where you can "tame" what's going in to the server.
Hope this helps!
Thank you, getRawValue() is the solution.
great!
Glad we could be of help! Thanks for the feedback!
I share other few lines to keep backwards compatibility.
My JsObject values are assumed to be DateTime and not String; so using those as SqlCommand Parameters, SQL Server handles datetime conversion in unpredictable way (in my case wrong because of Italian OS over US Sql server).
Assuming to have more than one parameter inside a JsObject I did this way
Code:public IActionResult OnPostClickMeButtonClick(JsObject jObj)
{
foreach (var obj in jObj)
{
if (Microsoft.VisualBasic.Information.IsDate(obj.Value.Value)) obj.Value.Value = DateTime.Parse(obj.Value.Value.ToString());
}
[...]
}
Hello again @bbros! Thanks for sharing the bits that helped you expand on the goal you have there.
I'm not sure it is safe to let it convert to DateTime, as again, it may imply time zone to the server and, if you move to another server, or if you distribute the load in different servers, they can differently "assume" this or that time zone.
If this is also a concern for you, and you want to keep usingJsObject
, it'd probably be a good idea to wrap your parameter in double quotes to ensure it is passed and interpreted as a string, and you extract the date segments from the string instead of letting the system go with conversions. Basically I'm raising up what was suggested in this post in our concurrent thread.
Of course in case it is convenient a conversion and don't bring any trouble for you, it'd be fine to leave as-is. Just keep an eye open for subtle changes in the date values as it is inserted in the database.
Thanks again for the follow up!
Hello, even I was still thinking of a bomb-proof solution.
I believe that if the page seds a value that for me is well-defined, I am able to calculate how many minutes has been modified by the POST method.
So the project could be modified by inserting a hidden field that contains the date 2020-01-01 (for example) and that is sent as a parameter.
Evaluating the offset of the value received with the date 2020-01-01 I can reconstruct the value that the user on the other side of the world would have liked to send me.
Changes are in lines 29-34, 47, 64-68
In this example, DateField is not hidden, server clock is GMT+2 and client clock is GMT+8.Code:using System;
using System.Collections.Generic;
using System.Globalization;
using Ext.Net;
using Ext.Net.Core;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace ExtCookbook.Pages
{
public class DateTimeZoneHandlingModel : PageModel
{
public FieldContainer MainContainer { get; set; }
public void OnGet()
{
MainContainer = new FieldContainer()
{
Anchor = "100%"
};
MainContainer.Items.Add(new DateField()
{
Id = "myDateField"
});
MainContainer.Items.Add(new TimeField()
{
Id = "myTimeField"
});
MainContainer.Items.Add(new DateField()
{
Id = "zuluTime",
Value = new DateTime(2020, 1, 1).ToShortDateString(),
FieldLabel = "zulu time offset calculator",
});
var btn = new Button()
{
Text = "Click me"
};
btn.DirectEvents.Click.Method = HttpMethod.POST;
btn.DirectEvents.Click.Url = $"?handler=ClickMeButtonClick";
btn.DirectEvents.Click.ExtraParams.Add(new DirectEventParameter() { Key = "myDate", Value = "App.myDateField.getValue()", Mode = ParameterMode.Raw });
btn.DirectEvents.Click.ExtraParams.Add(new DirectEventParameter() { Key = "myTime", Value = "App.myTimeField.getValue()", Mode = ParameterMode.Raw });
btn.DirectEvents.Click.ExtraParams.Add(new DirectEventParameter() { Key = "myDateString", Value = "App.myDateField.getRawValue()", Mode = ParameterMode.Raw });
btn.DirectEvents.Click.ExtraParams.Add(new DirectEventParameter() { Key = "myTimeString", Value = "App.myTimeField.getRawValue()", Mode = ParameterMode.Raw });
btn.DirectEvents.Click.ExtraParams.Add(new DirectEventParameter() { Key = "zuluTime", Value = "App.zuluTime.getValue()", Mode = ParameterMode.Raw });
MainContainer.Items.Add(btn);
}
public IActionResult OnPostClickMeButtonClick(JsObject jObj)
{
string postedDateValue = jObj.GetValueOrDefault("myDate").Value.ToString();
string postedTimeValue = jObj.GetValueOrDefault("myTime").Value.ToString();
var date = DateTime.Parse(postedDateValue, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal);
var time = DateTime.Parse(postedTimeValue, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal);
var dateString = DateTime.Parse(postedDateValue);
var timeString = DateTime.Parse(postedTimeValue);
DateTime postedZuluTimeValue = DateTime.Parse(jObj.GetValueOrDefault("zuluTime").Value.ToString());
var Offset = Microsoft.VisualBasic.DateAndTime.DateDiff(Microsoft.VisualBasic.DateInterval.Minute, new DateTime(2020, 01, 01), postedZuluTimeValue);
var realDate = DateTime.Parse(postedDateValue).AddMinutes(-Offset);
var realTime = DateTime.Parse(postedTimeValue).AddMinutes(-Offset);
this.X().Toast(@$"Posted date value is {postedDateValue} and converted to local time is {date.ToShortDateString()}; string value is {dateString}<br />
Posted date value is {postedTimeValue} and converted to local time is {time.ToShortTimeString()}; string value is {timeString}<br />
<b>Offset in minutes is {Offset}</b></br>
Submitted date value is <b>{realDate.ToShortDateString()}</b> and time is <b>{realTime.ToShortTimeString()}</b>");
return this.Direct();
}
}
}
And the result is in this image:
Attachment 25556
About conversion from string I fear to get different format depending on the user local settings.
I mean, here in Italy date to string is dd/MM/yyyy, but in US is MM/dd/yyyy.
I don't know if 01/02/2003 is 1st of february or 2nd of january.