I have C# program where all DateTime
objects are DateTimeKind.UTC
. When saving the objects to the database it stores UTC as expected. However, when retrieving them, they are DateTimeKind.Unspecified
. Is there a way to tell Entity Framework (Code First) when creating DateTime
objects in C# to always use DateTimeKind.UTC
?
To convert the time in a non-local time zone to UTC, use the TimeZoneInfo. ConvertTimeToUtc(DateTime, TimeZoneInfo) method. To convert a time whose offset from UTC is known, use the ToUniversalTime method. If the date and time instance value is an ambiguous time, this method assumes that it is a standard time.
Entity Framework DateTime format when editing entry Id... and ... Date.... It's defined as so:...public class Timetable { public int Id { get; set; } [Required, Column(TypeName = "Date"), DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")] public DateTime Date { get; set; } } ... I then scaffolded some basic...
The SpecifyKind method creates a new DateTime object using the specified kind parameter and the original time value. The returned DateTime value does not represent the same instant in time as the value parameter, and SpecifyKind is not a time zone conversion method.
The DateTimeOffset structure includes a DateTime value, together with an Offset property that defines the difference between the current DateTimeOffset instance's date and time and Coordinated Universal Time (UTC).
No, there's not. And it's actually DateTimeKind.Unspecified
.
However, if you are concerned about supporting multiple timezones, you should consider using DateTimeOffset. It's like a regular DateTime, except that it does not represent a "perspective" of time, it represents an absolute view, in which 3PM (UTC - 3) equals 4PM (UTC - 2). DateTimeOffset contains both the DateTime and the time zone and it's supported by both EntityFramework and SQL Server.
You can have your datacontext fix up all the relevant values as it goes. The following does so with a cache of properties for entity types, so as to avoid having to examine the type each time:
public class YourContext : DbContext
{
private static readonly List<PropertyInfo> EmptyPropsList = new List<PropertyInfo>();
private static readonly Hashtable PropsCache = new Hashtable(); // Spec promises safe for single-reader, multiple writer.
// Spec for Dictionary makes no such promise, and while
// it should be okay in this case, play it safe.
private static List<PropertyInfo> GetDateProperties(Type type)
{
List<PropertyInfo> list = new List<PropertyInfo>();
foreach(PropertyInfo prop in type.GetProperties())
{
Type valType = prop.PropertyType;
if(valType == typeof(DateTime) || valType == typeof(DateTime?))
list.Add(prop);
}
if(list.Count == 0)
return EmptyPropsList; // Don't waste memory on lots of empty lists.
list.TrimExcess();
return list;
}
private static void FixDates(object sender, ObjectMaterializedEventArgs evArg)
{
object entity = evArg.Entity;
if(entity != null)
{
Type eType = entity.GetType();
List<PropertyInfo> rules = (List<PropertyInfo>)PropsCache[eType];
if(rules == null)
lock(PropsCache)
PropsCache[eType] = rules = GetPropertyRules(eType); // Don't bother double-checking. Over-write is safe.
foreach(var rule in rules)
{
var info = rule.PropertyInfo;
object curVal = info.GetValue(entity);
if(curVal != null)
info.SetValue(entity, DateTime.SpecifyKind((DateTime)curVal, rule.Kind));
}
}
}
public YourContext()
{
((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += FixDates;
/* rest of constructor logic here */
}
/* rest of context class here */
}
This can also be combined with attributes so as to allow one to set the DateTimeKind
each property should have, by storing a set of rules about each property, rather than just the PropertyInfo
, and looking for the attribute in GetDateProperties
.
My solution, using code first: Declare the DateTime properties in this way:
private DateTime _DateTimeProperty;
public DateTime DateTimeProperty
{
get
{
return _DateTimeProperty;
}
set
{
_DateTimeProperty = value.ToKindUtc();
}
}
Also can create the property as:
private DateTime? _DateTimeProperty;
public DateTime? DateTimeProperty
{
get
{
return _DateTimeProperty;
}
set
{
_DateTimeProperty = value.ToKindUtc();
}
}
ToKindUtc()
is a extension to change DateTimeKind.Unspecified
to DateTimeKind.Utc
or call ToUniversalTime()
if kind is DateTimeKind.Local
Here the code for the extensions:
public static class DateTimeExtensions
{
public static DateTime ToKindUtc(this DateTime value)
{
return KindUtc(value);
}
public static DateTime? ToKindUtc(this DateTime? value)
{
return KindUtc(value);
}
public static DateTime ToKindLocal(this DateTime value)
{
return KindLocal(value);
}
public static DateTime? ToKindLocal(this DateTime? value)
{
return KindLocal(value);
}
public static DateTime SpecifyKind(this DateTime value, DateTimeKind kind)
{
if (value.Kind != kind)
{
return DateTime.SpecifyKind(value, kind);
}
return value;
}
public static DateTime? SpecifyKind(this DateTime? value, DateTimeKind kind)
{
if (value.HasValue)
{
return DateTime.SpecifyKind(value.Value, kind);
}
return value;
}
public static DateTime KindUtc(DateTime value)
{
if (value.Kind == DateTimeKind.Unspecified)
{
return DateTime.SpecifyKind(value, DateTimeKind.Utc);
}
else if (value.Kind == DateTimeKind.Local)
{
return value.ToUniversalTime();
}
return value;
}
public static DateTime? KindUtc(DateTime? value)
{
if (value.HasValue)
{
return KindUtc(value.Value);
}
return value;
}
public static DateTime KindLocal(DateTime value)
{
if (value.Kind == DateTimeKind.Unspecified)
{
return DateTime.SpecifyKind(value, DateTimeKind.Local);
}
else if (value.Kind == DateTimeKind.Utc)
{
return value.ToLocalTime();
}
return value;
}
public static DateTime? KindLocal(DateTime? value)
{
if (value.HasValue)
{
return KindLocal(value.Value);
}
return value;
}
}
Remember to include in the model's file.
using TheNameSpaceWhereClassIsDeclared;
The set method of property is called when reading from datatabase with EF, or when assigned in a MVC controller's edit method.
Warning, if in web forms, if you edit dates in local timezone, you MUST convert the date to UTC before send to server.
Have a look on the michael.aird answer here: https://stackoverflow.com/a/9386364/279590 It stamp the date UTC kind during loading, with an event on ObjectMaterialized.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With