.NET6 和 DateTime 问题。无法将 Kind=UTC 的 DateTime 写入 PostgreSQL 类型“没有时区的时间戳”

Posted

技术标签:

【中文标题】.NET6 和 DateTime 问题。无法将 Kind=UTC 的 DateTime 写入 PostgreSQL 类型“没有时区的时间戳”【英文标题】:.NET6 and DateTime problem. Cannot write DateTime with Kind=UTC to PostgreSQL type 'timestamp without time zone' 【发布时间】:2021-11-14 08:31:26 【问题描述】:

我有一个常见的问题。

无法将 Kind=UTC 的 DateTime 写入 PostgreSQL 类型 'timestamp 没有时区'

我想启用 Legacy Timestamp 行为,如此处所述: https://github.com/npgsql/doc/blob/main/conceptual/Npgsql/types/datetime.md/

public MyDbContext(DbContextOptions<MyDbContext> contextOptions) : base(contextOptions)
        
            AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
            AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
        

但不起作用。我仍然遇到同样的错误。

我做错了什么。为什么遗留行为不起作用?

【问题讨论】:

你必须分享一些代码来显示你在做什么,以及堆栈跟踪的完整异常。 重大更改github.com/npgsql/efcore.pg/issues/2000 【参考方案1】:

一个。添加解决

AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);StartupConfigure 方法。


B。或者,如果您根本没有 Startup 类,并且您的所有初始化都在带有主机构建器的 Program.cs 中,那么您的文件结尾可能如下所示:

... //adding services etc
var host = builder.Build();
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
... //your other scoped code
await host.RunAsync();

要使用System.Linq.Dynamic查询数据库,我们还需要指定时间类型。 过滤器示例: $"User.BirthDate&gt;=time.ToStringUtc()"

public static string ToStringUtc(this DateTime time)

    return $"DateTime(time.Ticks, DateTimeKind.Utc)";


同时,@istvan-kardkovacs 的回答 https://***.com/a/70142836/7149454 也适用。基本上是为您正在创建的每个= new DateTime() 添加一个 .SetKindUtc()。在执行任何其他代码之前,在填充数据库的后台托管服务中,上面的开关显然对我不起作用。

【讨论】:

当切换到 .net 6(从核心 3.1)我得到这个错误,这是解决它的最简单方法【参考方案2】:

您必须为创建、插入、更新操作中的所有 DateTime 字段以及 Linq 查询中的 DateTime 比较设置 DateTimeKind。 我创建了一个小型扩展方法并添加到所有日期字段。

public static class DateTimeExtensions

    public static DateTime? SetKindUtc(this DateTime? dateTime)
    
        if (dateTime.HasValue)
        
            return dateTime.Value.SetKindUtc();
        
        else
        
            return null;
        
    
    public static DateTime SetKindUtc(this DateTime dateTime)
    
        if (dateTime.Kind == DateTimeKind.Utc)  return dateTime; 
        return DateTime.SpecifyKind(dateTime, DateTimeKind.Utc);
    

【讨论】:

【参考方案3】:

我在我的DbContext 中添加了代码,以便在我的模型上的所有日期属性上进行设置:

//dbcontext
public override int SaveChanges()

    _changeTrackerManager?.FixupEntities(this);
    return base.SaveChanges();


//don't forget the async method!
public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default)

    _changeTrackerManager?.FixupEntities(this);
    return base.SaveChangesAsync();

这个IChangeTrackerManager 依赖将被注入,然后任何时候实体被保存,它会调用下面的这个方法来修正所有的UTC日期时间类型。

public void FixupEntities(DbContext context)

    var dateProperties = context.Model.GetEntityTypes()
        .SelectMany(t => t.GetProperties())
        .Where(p => p.ClrType == typeof(DateTime))
        .Select(z => new
        
            ParentName = z.DeclaringEntityType.Name,
            PropertyName = z.Name
        );

    var editedEntitiesInTheDbContextGraph = context.ChangeTracker.Entries()
        .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified)
        .Select(x => x.Entity);

    foreach (var entity in editedEntitiesInTheDbContextGraph)
    
        var entityFields = dateProperties.Where(d => d.ParentName == entity.GetType().FullName);

        foreach (var property in entityFields)
        
            var prop = entity.GetType().GetProperty(property.PropertyName);

            if (prop == null)
                continue;

            var originalValue = prop.GetValue(entity) as DateTime?;
            if (originalValue == null)
                continue;

            prop.SetValue(entity, DateTime.SpecifyKind(originalValue.Value, DateTimeKind.Utc));
        
    

【讨论】:

【参考方案4】:

当我的控制器反序列化对象并且我尝试使用 EF 和 Npgsql.EntityFrameworkCore.PostgreSQL 插入/更新它时,我也发生了同样的事情。我对所有日期都使用了 ToUniversalTime(),它对我有用。

【讨论】:

【参考方案5】:

我找到了答案。不要将这些行添加到您的 dB 上下文中。而是在 WFP 应用程序中添加到 MainWindow.xaml.cs,如下所示:

在前面添加“EnableLegacyTimestampBehavior”行 公共 MainWindow 方法中的 InitializeComponent 语句。

您不需要“DisableDateTimeInfinityConversions”语句。

您的带有 DateTime 的代码现在可以工作了。

【讨论】:

【参考方案6】:

从@DLeh 稍微修改https://***.com/a/71179214/507421

    private void ConvertDateTimesToUniversalTime()
    
        var modifiedEntites = ChangeTracker.Entries<IHaveAggregateRootId>()
                .Where(e => (e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted)).ToList();
        foreach (var entry in modifiedEntites)
        
            foreach (var prop in entry.Properties)
            
                if (prop.Metadata.ClrType == typeof(DateTime))
                
                    prop.Metadata.FieldInfo.SetValue(entry.Entity, DateTime.SpecifyKind((DateTime)prop.CurrentValue, DateTimeKind.Utc));
                
                else if (prop.Metadata.ClrType == typeof(DateTime?) && prop.CurrentValue != null)
                
                    prop.Metadata.FieldInfo.SetValue(entry.Entity, DateTime.SpecifyKind(((DateTime?)prop.CurrentValue).Value, DateTimeKind.Utc));
                
            
        
    

【讨论】:

【参考方案7】:

就我而言,这是我犯的一个错误

InvitedOn = DateTime.Now

应该是

InvitedOn = DateTime.UtcNow

成功了

【讨论】:

以上是关于.NET6 和 DateTime 问题。无法将 Kind=UTC 的 DateTime 写入 PostgreSQL 类型“没有时区的时间戳”的主要内容,如果未能解决你的问题,请参考以下文章

无法将 MySQL 日期/时间值转换为 System.DateTime

Pandas 和 DateTime TypeError:无法将 TimedeltaIndex 与浮点类型进行比较

php 如何将数据库中读出的datetime类型的时间转化成date类型的时间。 循环过程也需要。

在 Mac 上的 VS Code 中在 .NET6 MVC 项目上使用 Serilog 时出现问题

无法将 DateTime 从 SQL Server 转换为 C# DateTime

无法比较天真和有意识的 datetime.now() <= challenge.datetime_end