.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);
到Startup
Configure
方法。
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>=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 时出现问题