You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4.0 KiB

PostgreSQL DateTime 时间戳问题修复总结

问题描述

在PostgreSQL数据库中,当使用timestamp with time zone类型时,只支持UTC时间的DateTime值。错误信息:

Cannot write DateTime with Kind=Unspecified to PostgreSQL type 'timestamp with time zone', only UTC is supported.

问题分析

1. 根本原因

  • PostgreSQL的timestamp with time zone类型要求DateTime的Kind必须是UTC
  • 代码中虽然使用了DateTime.UtcNow,但实体配置中没有明确指定数据库列类型
  • 响应类中使用了DateTime.UtcNow而不是从实体中获取的时间

2. 问题位置

  1. 实体配置类:缺少.HasColumnType("timestamp with time zone")配置
  2. 响应构建:使用了DateTime.UtcNow而不是实体的时间字段

修复方案

1. 修复的实体配置类

Device相关

  • ProtocolVersionConfiguration
  • CellularDeviceConfiguration

Identity相关

  • AppRoleConfiguration
  • AppUserConfiguration

其他

  • BaseEntityConfiguration
  • PermissionConfiguration
  • LoginLogConfiguration

2. 修复的CommandHandler响应

ProtocolVersion相关

  • UpdateProtocolVersionCommandHandler:使用existingProtocolVersion.UpdatedAt

Device相关

  • UpdateDeviceCommandHandler:使用existingDevice.UpdatedAt

3. 修复内容

实体配置类修复

// 修复前
builder.Property(e => e.CreatedAt)
    .IsRequired()
    .HasComment("创建时间");

// 修复后
builder.Property(e => e.CreatedAt)
    .IsRequired()
    .HasColumnType("timestamp with time zone")
    .HasComment("创建时间");

响应构建修复

// 修复前
UpdatedAt = DateTime.UtcNow

// 修复后
UpdatedAt = existingEntity.UpdatedAt

修复的字段类型

1. 时间戳字段

  • CreatedAt / CreatedTime:创建时间
  • UpdatedAt / ModifiedTime:更新时间
  • LastLoginTime:最后登录时间
  • LoginTime:登录时间
  • ReleaseDate:发布日期

2. 数据库类型

  • PostgreSQL: timestamp with time zone
  • 确保所有DateTime字段都使用UTC时间

最佳实践

1. 时间处理原则

// ✅ 正确:使用UTC时间
DateTime.UtcNow

// ❌ 错误:使用本地时间
DateTime.Now

// ❌ 错误:使用未指定Kind的时间
new DateTime(2024, 1, 1)

2. 实体配置

// ✅ 正确:明确指定PostgreSQL时间戳类型
builder.Property(e => e.CreatedAt)
    .HasColumnType("timestamp with time zone");

// ❌ 错误:依赖默认类型推断
builder.Property(e => e.CreatedAt);

3. 响应构建

// ✅ 正确:使用实体的时间字段
response.UpdatedAt = entity.UpdatedAt;

// ❌ 错误:重新生成时间
response.UpdatedAt = DateTime.UtcNow;

数据库迁移

1. 现有数据库

如果数据库中已有数据,需要确保:

  • 所有DateTime字段都存储为UTC时间
  • 列类型为timestamp with time zone

2. 新数据库

  • 实体配置会自动生成正确的列类型
  • 所有时间字段都会使用UTC时间

验证方法

1. 代码验证

// 检查DateTime.Kind
if (entity.CreatedAt.Kind != DateTimeKind.Utc)
{
    throw new InvalidOperationException("DateTime must be UTC");
}

2. 数据库验证

-- 检查列类型
SELECT column_name, data_type 
FROM information_schema.columns 
WHERE table_name = 'your_table' 
AND column_name LIKE '%time%';

-- 检查时间值
SELECT created_at, updated_at 
FROM your_table 
LIMIT 5;

总结

这次修复确保了:

  1. 数据类型一致性:所有DateTime字段都使用PostgreSQL的timestamp with time zone类型
  2. 时间标准统一:所有时间都使用UTC标准
  3. 配置明确性:实体配置中明确指定了数据库列类型
  4. 响应准确性:响应中使用实体的实际时间而不是重新生成的时间

这种修复方式为整个系统提供了统一的时间处理标准,确保了与PostgreSQL数据库的完全兼容性。