C#-“DateTime.UtcNow”以一种格式输出日期,该格式被视为超出 Postgres DB 的范围

Posted

技术标签:

【中文标题】C#-“DateTime.UtcNow”以一种格式输出日期,该格式被视为超出 Postgres DB 的范围【英文标题】:C#- "DateTime.UtcNow" outputs date in a format which is treated as out of range for Postgres DB 【发布时间】:2022-01-17 20:23:04 【问题描述】:

我已转移到一台新笔记本电脑(Windows 10 i5)并尝试设置我的 .NET 应用程序。我遇到了一个奇怪的问题,这花了我很多时间。在我的应用程序中,我将当前日期时间以 UTC 格式存储在 Postgres DB 表中。 c#命令DateTime.UtcNow输出日期格式为

14-12-2021 13:50:57

当通过插入查询传递上述日期以存储在 Postgres Db 中时,它会抛出错误

错误:日期/时间字段值超出范围:“14-12-2021 13:50:57”

似乎更奇怪的是,在我的旧笔记本电脑(相同的操作系统 - windows 10 i3)上,相同的代码可以正常工作,并给出日期的输出

2021 年 12 月 14 日上午 7:24:24

这种格式被 Postgres DB 接受。

表格设计如下

CREATE TABLE IF NOT EXISTS public."Log"
(
    "Id" bigint NOT NULL DEFAULT nextval('"Log_Id_seq"'::regclass),
    "QueueId" uuid NOT NULL,
    "MessageId" character varying(100) COLLATE pg_catalog."default",
    "LogTime" timestamp without time zone,   
   
    CONSTRAINT "Log_pkey" PRIMARY KEY ("Id")
)

DateTime.UtcNow 产生的值正在传递到 LogTime 列。

这是构成 Postgres 查询的 c# 代码。

string query = $@"INSERT INTO public.""Log""(
                            ""QueueId"", 
                            ""LogTime"", 
                            ""Message"", 
                            )
                            VALUES(
                            'req.QueueId', 
                            'req.LogTime', 
                            '(item.Message.Length > 100 ? item.Message.Substring(0, 100) : item.Message)'                           
                            RETURNING ""Id"";";

相同的代码在具有相同操作系统的不同机器上表现不同。任何线索将不胜感激。感谢您的帮助。

【问题讨论】:

您真的不应该以任何格式存储日期并在数据库中的这些列上使用日期/时间类型 如何将此值传递给您的数据库?您是直接或间接转换字符串中的日期时间变量,然后要求数据库将其转换回日期时间吗?请在您有插入逻辑的地方添加相关代码 请准确说明你在做什么 这几乎可以肯定是一个序列化问题(正如其他 cmets 中提到的)。您能否在问题中包含表格设计和写入表格的代码? For the 1024 time – DateTime has no format! 【参考方案1】:

我重复上面的评论,因为您在编写“req.LogTime”时正在转换字符串中的日期时间,并且代码会为您的数据库创建解析问题,因为它需要将该字符串转换回将其插入列中的时间跨度。这不仅在转换字符串时容易产生不同的结果(一台电脑认为日期的正确格式是“MM-dd”,另一台认为是“dd-MM”),而且它还产生了一个众所周知的漏洞称为 Sql 注入。 您应该简单地使用参数将值传递给您的数据库。 使用正确的类型定义参数,值的解析不会再有歧义,并且数据库不会受到尝试世界上最简单的 hack 的脚本孩子的影响。

string query = $@"INSERT INTO public.""Log""(
                  ""QueueId"", LogTime"", ""Message"")
                  VALUES(@qid, @ltime, @msg)                           
                  RETURNING ""Id"";";

using (var cmd = new NpgsqlCommand(query, conn))

    cmd.Parameters.Add("@qid", NpgsqlDbType.Uuid).Value = req.QueueId;
    cmd.Parameters.Add("@ltime", NpgsqlDbType.Timestamp).Value = req.LogTime;
    cmd.Parameters.Add("@msg", NpgsqlDbType.Varchar).Value = 
         (item.Message.Length > 100 ? item.Message.Substring(0, 100) : item.Message);
   var id = cmd.ExecuteScalar();

【讨论】:

在这种情况下编写正确的代码比编写错误的代码要简单。如果使用 Dapper,这将变成 4 行,包括查询 @Steve,我能理解你的意思。请理解,这是一个 POC,而不是生产代码。在它成为生产代码之前,所有相关的点都会被整理出来。现在,这不是我关心的问题,因为我说过相同的代码可以在不同的笔记本电脑上工作,但不是这个。 我不知道还能说什么。我已经解释了我认为不稳定行为的原因以及如何解决它。 @Steve,我知道您的解决方案无论如何都会解决它。但我的意思不是要得到这种情况的答案,而是要得到这种情况的原因。问题是,我不确定为什么相同的代码在两台不同的机器上表现不同。 我想我已经在我的回答中解释过了。客户端 PC 将转换为字符串的日期发送到您的服务器。它要求底层的 ToString() 将该日期格式化为字符串,但这种转换发生在客户端 PC 中,它具有关于日期表示的规则。服务器无法将该字符串恢复为日期,因为它对应如何写入表示日期的字符串有不同的理解。

以上是关于C#-“DateTime.UtcNow”以一种格式输出日期,该格式被视为超出 Postgres DB 的范围的主要内容,如果未能解决你的问题,请参考以下文章

DateTime.Now/UtcNow 默认文化 - 客户端还是服务器?

DateTime.UtcNow.ToString() 和DateTime.Now.ToString()输出的字符为啥不一样呢?

DateTime.Now 和DateTime.UtcNow的区别

C#DateTime.Now precision

DateTime.Now 与 DateTime.UtcNow

DateTime.UtcNow 协调通用时间(UTC)