Saltar al contenido

Cómo especificar que los objetos DateTime recuperados de EntityFramework deben ser DateTimeKind.UTC

Hola, tenemos la respuesta a lo que buscas, has scroll y la verás más abajo.

Solución:

No, no lo hay. Y en realidad es DateTimeKind.Unspecified.

Sin embargo, si le preocupa admitir varias zonas horarias, debería considerar el uso de DateTimeOffset. Es como un DateTime normal, excepto que no representa una “perspectiva” de tiempo, representa una vista absoluta, en la que 3PM (UTC – 3) es igual a 4PM (UTC – 2). DateTimeOffset contiene tanto el DateTime como la zona horaria y es compatible con EntityFramework y SQL Server.

Puede hacer que su contexto de datos corrija todos los valores relevantes a medida que avanza. Lo siguiente lo hace con un caché de propiedades para tipos de entidad, para evitar tener que examinar el tipo cada vez:

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())
     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 */

Esto también se puede combinar con attributes para permitir que uno establezca el DateTimeKind cada propiedad debe tener, almacenando un conjunto de reglas sobre cada propiedad, en lugar de solo las PropertyInfo, y buscando el attribute en GetDateProperties.

Mi solución, usando el código primero: Declare las propiedades de DateTime de esta manera:

private DateTime _DateTimeProperty;
public DateTime DateTimeProperty

    get
    
        return _DateTimeProperty;
    
    set
    
        _DateTimeProperty = value.ToKindUtc();
    

También puede crear la propiedad como:

private DateTime? _DateTimeProperty;
public DateTime? DateTimeProperty

    get
    
        return _DateTimeProperty;
    
    set
    
        _DateTimeProperty = value.ToKindUtc();
    

ToKindUtc() es una extensión para cambiar DateTimeKind.Unspecified para DateTimeKind.Utc o llamar ToUniversalTime() si el tipo es DateTimeKind.Local
Aquí el código para las extensiones:

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;
    

Recuerda incluirlo en el archivo del modelo.

using TheNameSpaceWhereClassIsDeclared;

Se llama al método de propiedad set cuando se lee desde la base de datos con EF, o cuando se asigna en el método de edición de un controlador MVC.

Advertencia, si en formularios web, si edita fechas en la zona horaria local, DEBE convertir la fecha a UTC antes de enviarla al servidor.

Si conservas algún traba y forma de regenerar nuestro ensayo puedes escribir una explicación y con deseo lo interpretaremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *