如何指定从EntityFramework检索的DateTime对象应该是DateTimeKind.UTC

我有C#程序,其中所有DateTime对象都是DateTimeKind.UTC 。 将对象保存到数据库时,它按预期存储UTC。 但是,在检索它们时,它们是DateTimeKind.Unspecified 。 有没有办法告诉entity framework(代码优先)在C#中创建DateTime对象时总是使用DateTimeKind.UTC

不,没有。 它实际上是DateTimeKind.Unspecified

但是,如果您担心支持多个时区,则应考虑使用DateTimeOffset 。 它类似于常规DateTime,除了它不代表时间的“视角”,它代表绝对视图,其中3PM(UTC – 3)等于4PM(UTC – 2)。 DateTimeOffset包含DateTime和时区,并且EntityFramework和SQL Server都支持它。

你可以让你的datacontext修复所有相关的值。 以下是实体类型的属性缓存,以避免每次都检查类型:

 public class YourContext : DbContext { private static readonly List EmptyPropsList = new List(); 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 GetDateProperties(Type type) { List list = new List(); 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 rules = (List)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 */ } 

这也可以与属性组合,以便允许人们通过存储关于每个属性的一组规则而不仅仅是PropertyInfo来设置每个属性应该具有的DateTimeKind ,并在GetDateProperties查找属性。

我的解决方案,首先使用代码:以这种方式声明DateTime属性:

 private DateTime _DateTimeProperty; public DateTime DateTimeProperty { get { return _DateTimeProperty; } set { _DateTimeProperty = value.ToKindUtc(); } } 

也可以创建属性:

 private DateTime? _DateTimeProperty; public DateTime? DateTimeProperty { get { return _DateTimeProperty; } set { _DateTimeProperty = value.ToKindUtc(); } } 

ToKindUtc()是将DateTimeKind.Unspecified更改为DateTimeKind.Utc或调用ToUniversalTime()的扩展,如果kind为DateTimeKind.Local这里是扩展的代码:

 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; } } 

请记住包含在模型的文件中。

 using TheNameSpaceWhereClassIsDeclared; 

使用EF从数据库读取时,或者在MVC控制器的编辑方法中分配时,将调用set属性方法。

警告,如果在Web表单中,如果您在本地时区编辑日期,则必须在发送到服务器之前将日期转换为UTC。

看一下michael.aird这里的答案: https : //stackoverflow.com/a/9386364/279590它在加载过程中标记了UTC种类,在ObjectMaterialized上有一个事件。