How to handle Datetime for different ui cultures - c#

In a web mvc5 application which supports en_Us and nb-NO cultures , How can i handle a Datetime object.
I have a ExpiryDate property in model .
How can i define the ExpDate property? What DisplayFormat i have to apply ? How can i convert that back in UI as per culture ? How can i save the data to SQlServer db as a valid datetime etc
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:DD.MM.YYYY}", ApplyFormatInEditMode = true)]
public Nullable<System.DateTime> ExpDate { get; set; }
Does this helps [ which is not happening to me ]. Still confused on how to use the model in Controller and inside View while fecthing and saving data
Is any one knows some well written articles covering these aspects or any one can post some examples s\to solve this?

In general a good approach to handling these Globalization issues is to always save DateTimes as UTC on the database and also to work with UTC format at the business logic level.
In fact since you do not know until it is render time at UI which culture the user selected to see ( and not only the culture but also the time-zone ), better to stick and work with UTC values and also with a format independent approach, meaning that you should not convert the DateTime from/to string value ever anywhere else than to render in the UI or to get it from data entry form.
If you did not read anything else up to now, I would start with this article: Beginner's Tutorial on Globalization and Localization in ASP.NET MVC
or simply google by ASP.NET MVC Globalization.
good luck

Related

Is it bad to convert c# datetime properties in the get and set to and from utc

In our Entity Framework app we are storing datetimes as UTC. The client uses a reflection utility to convert object graphs to their users timezone, and then back to utc when submitting changes to the server.
The utility works fine, but i'm considering a cleaner approach where I add a unmapped TimeZoneInfo property on the base class with a default value set to UTC, and then for each datetime property i would modify it like so:
private DateTime _endTime;
public DateTime EndTime
{
get
{
return _endTime.ConvertFromUtc(TimeZone);
}
set
{
_endTime = value.ConvertToUtc(TimeZone);
}
}
The idea is that the backing field is always stored as a UTC value. If the TimeZone proeprty is set to UTC, then the ConvertTo/From extension methods will not do any conversion and will simply return the backing fields value. Whereas, if the TimeZone is set to anything else then the conversion will take place, leaving the backing field in UTC.
What i'm wondering is if there are issues i'm not thinking of. For instance, I'm assuming it would serialize with a value based on the current TimeZone property...is that true? Also, would this work for code first entities in EF? My hope is that if the TimeZone is changed it would not trigger a change in the dbcontext. Are there any other considerations that i'm missing that would make this a bad idea, and what would a DDD implementator think?
Edit
To clarify the use case a little more, the service layer will retrieve the values from the db, serialize, and send it to the MVC Controller. The service layer does not know of the users timezone. In my mvc app the web controller cached the user timezone at logon. This controller will then use that value to set the TimeZone property on the object. It will then submit it to the client via JSON. The TimeZone property on the base class represents the current timzone of the object, not the users timezone. The values are always stored as UTC and the controller which sends the data to the client is responsible to make sure it is set to the correct timezone.
The biggest reason i am considering this is for business logic. The object in question is a schedule which has a start and end time. There are three requirements that would be easier to perform if the object were set to the users timezone. For instance, schedules cannot span weeks, so if it starts on Saturday (end of week) and ends on Sunday (start of week) it must be split into two different schedules. For some reason i have a more difficult time when working with datetime logic, and so anything i can do to simplify it is a plus for maintenance.
The thing is that your application's timezone will be the web server's timezone! If the user is visiting your site from another timezone, the conversion will be wrong.
You need to make your page determine via the browser what their timezone is and use that for conversions.
If you need the user's current time, you can use this:
Date.now()
// Or this if you need support for old browsers, like IE8
new Date().getTime()
That will give you UTC time in milliseconds since January 1st 1970. You will have to later convert that to C# time by doing this in your application:
DateTime date = new DateTime(valueFromJS * 10000 + 621355860000000000);
If you don't need the current time but a date+time entered by the user in a date picker, then you should create a date object in the browser from that and send the getTime() of that object. This way your web server always receives UTC time and it's up to the browser do the appropriate conversion.
You can also use new Date().getTimezoneOffset(), which will return the amount of minutes UTC is ahead of the user timezone. So if the user is in GMT -4, that function will return 240. If for some reason you need that in the web server, you can send that value from the browser. Alternatively, if your application has users, you can even store that as a setting and simply use that.
Now, to display the date in the browser's timezone, you have to either know beforehand the user's timezone (from a previous request or a user setting) or just send it in UTC and then convert that via JavaScript in the browser.
There are also useful libraries to deal with timezone problems. For example:
http://momentjs.com/timezone/
http://tzdata-javascript.org
I do not think my question was well worded, nor thought out. I decided to implement the above idea into part of my project and found that it just creates more confusion than it's worth. It's also adds too much risk, especially if used in objects that are persisted to the db, where a programmer may fail to convert the object back to utc.
Instead i am adding a much, much simpler way by adding an extension method to easily calculate based on a specified timezone. The extension method assumes the datetime object is in UTC:
public static DateTime? As(this DateTime? dt, TimeZoneInfo targetTimeZone)
{
if (dt.HasValue)
return dt.Value.As(targetTimeZone);
else
return dt;
}
public static DateTime As(this DateTime dt, TimeZoneInfo targetTimeZone)
{
return TimeZoneInfo.ConvertTimeFromUtc(dt, targetTimeZone);
}
This ensures the underlying object is not mutated unnecessarily.

DateTime Conversion in Entity Framework

I'm trying to insert a datetime value to my database. I'm using entity framework with ASP.NET MVC 4 and SQL server.
using (dc = new GateEntities())
{
tblSite site = new tblSite();
site.CalledInAt = DateTime.Parse("19/09/2013 00:29 AM", new CultureInfo("en- US", false));
dc.tblSites.Add(site);
dc.SaveChanges();
}
When I try to save the data I get the error:
"The value '19/09/2013 00:29 AM' is not valid for CalledInAt."
I also tried Convert.ToDateTime() but no use.
This works fine in my local machine. It's not working only on my shared hosting server.
There are two errors in the code you list.
The first (which I guess is an error introduced while typing the question) is that your CultureInfo is being set to 'en- US' which should be 'en-US'
The other is that US dates are formatted Month then Day and in your string that would make the date you are setting the 19th month of the year.
This code below works for your date value...
DateTime.Parse("09/19/2013 00:29 AM", new System.Globalization.CultureInfo("en-US", false));
The exception is caused by EF's validation which happens in a culture that has a different date format than the string 19/09/2013 00:29 AM.
When it comes to assigning values to entity properties from user input, the best approach is to make sure that you are independent of UI culture. This means that in the UI (probably a view model) you have to capture user input and convert it to a DateTime value. Then you just assign the DateTime value to site.CalledInAt.
Another option is to include the UI culture in the view model and use it to do the conversion in the controller.
I set the culture in web.config and it started working.
<globalization uiCulture="en" culture="en-GB" />

Show date part only

I would like to display only the date on the page.
SQL column has type date.
Model
public System.DateTime EndDate { get; set; }
View
#Html.DisplayFor(modelItem => item.EndDate.Date)
This gives me no warnings or errors, however the time is still displaying on the page.
DateTime.Date returns a new instance of DateTime with the time component set to midnight (rather than removing the Time completely), it's only useful for normalizing date/time values and is not intended for display purposes.
Anyway, you don't need DisplayFor, you can render the date directly:
#item.EndDate.ToString("yyyy-MM-dd")
You can use theDate.ToShortDateString() or use a custom date/time string format.
The benefit of ToShortDateString() is that it is CULTURALLY SENSITIVE making your application more accessible.
If you want to use the Html.DisplayFor template helper then you may want to build a ShortDateTime.cshtml display template. Learn more about that here:
https://stackoverflow.com/a/6001836/941058
Try the ToString() date formatters:
http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx
Example:
#Html.DisplayFor(modelItem => item.EndDate.Date.ToString("MMMM dd, yyyy")

ASP.NET MVC3 Best way to customize converting input parameters

I'm going to add support of different timezone in my ASP.NET MVC3 app.
The solution is to store date values in UTC time, and store user timezone offset.
So, I need 2 things:
Send date values to user in "user time" (it's clear, I pass date to wrapper that convert time to user time)
Retrieve date from user in "user time" and convert it to UTC.
Question is - what is the nice way to convert all input date values to UTC time. Or is there a generic way to add some converting rules to ASP.NET MVC ?
This is ideal schema what I want (controller receive already converted values)
A way could be to create your own ModelBinder that do the work of mapping and preparing the data for your action method in the controller.
This post from Hanselman's Blog should give you an idea of what I mean. Obviously I'm assuming that you can get all the data you need inside the method
BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
Like getting the user timezone with a repository or a hidden field in the post.

ASP.NET MVC 3 Binding & Validating Date to html textbox control

I have a SmallDateTime field in my Sql Server 2008 database to store users Birthdays.
On my 'Edit Profile' web page, I have a standard textbox which I want to bind the 'Birthday' date to (excluding the time as this is not required). At present I am binding to the textbox but it is rendering the full Date and Time.
In addition, when the user updates their profile, I want to be able to validate the Birthday textbox, ensuring that the value specified complies to dd/mm/yyyy, and any deviation from that is highlighted via my existing validation summary on the page.
How do I go about:
a) configuring the Birthday property in my ViewModel to display in dd/mm/yyyy format (excluding the time).
b) validate Birthday (based on dd/mm/yyyy format) when the user submits the form?
[DisplayFormat(DataFormatString="{0:dd/MM/yyyy}", ApplyFormatInEditMode=true)]
public DateTime DateOfBirth { get; set; }
This should give you the automatic formatting on the field (without you having to manually do it) and also the validation.
I usually use a string property paired with the DateTime object, something like
public string MyDateStr
{
get
{
return MyDateDate == null ? "" : MyDateDate.ToShortDateString();
}
set
{
// Usually a tryParse for the string value
}
}
I know that is not the canonical way, but up to now, is the fastest I've found.
HTH
M.
EDIT: for the validation stuff see this:other question on SO
a) you can use .ToShortDateString to render your datetime without time. Format still depends on globalization defaults.
b) to validate, you could do it with Data Annotations on your model like this:
[DataType(DataType.DateTime, ErrorMessage = "Please enter a valid date in the format dd/mm/yyyy")]
public DateTime Birthday { get; set; }

Categories

Resources