【问题标题】:C# TimeZone info lost when assigning DateTime to DataRow [duplicate]将 DateTime 分配给 DataRow 时 C# TimeZone 信息丢失 [重复]
【发布时间】:2013-07-12 13:26:20
【问题描述】:

正如标题所说,在我为 DateTime 对象分配时区 UTC 后,它在分配给 DataRow 时会丢失其 TimeZone 信息。

static void Main(string[] args)
  {
     DateTime universalTime = DateTime.UtcNow;

     DataTable table = new DataTable();
     table.Columns.Add("Time", typeof(DateTime));
     DataRow row = table.NewRow();

     row["Time"] = universalTime;

     /* writes Kind: Utc */
     Console.WriteLine("Universal time      : " + universalTime + ", kind: " + universalTime.Kind);

     /* writes Kind: Unspecified */
     Console.WriteLine("Same time in DataRow: " + row["Time"] + ", kind: " + ((DateTime)row["Time"]).Kind);

     Console.ReadKey();
  }

分配给 DataRow 后,它显示 Kind = Unspecified。

这是 DataRow 中的错误还是我在这里做错了什么?

【问题讨论】:

  • 这有关系吗?对于在数据库中存储时间,存储为 UTC 是唯一有意义的格式。
  • dup 帖子有答案,但也要注意Kind 并没有真正保留时区信息。这只是一条规则,说明在与时区函数交互时应如何处理该值。无论如何,在保存数据时它通常不会持久化。您可以将UTC 视为一个时区,但LocalUnspecified 的种类有点不同。如果你追求的是持久性,你可能想看看DateTimeOffset。即使您的偏移量为零,它至少会以这种方式持久化并且不会丢失。

标签: c# timezone datarow


【解决方案1】:

我怀疑这是因为在持久层的 datetime 数据类型中没有可用的时区信息。

例如,在 SQL Server 上,datetime 类型没有时区信息。因此,DateTime 类型的任何 C# 值都只存储其值。这类似于 Linq-to-SQL 和实体框架的工作方式。

我的解决方法通常是为所有持久化的DateTime 值确定一个时区 (UTC),并在持久化之前和检索之后进行转换。

类似这样的:

public DateTime InputTime(DateTime time) {
    if (time.Kind == DateTimeKind.Unspecified) {
        throw new ArgumentException("Time values cannot be input to the data store with unspecified kind.");
    }
    return time.ToUniversalTime();
}

public DateTime OutputTime(DateTime time) {
    if (time.Kind == DateTimeKind.Unspecified) {
        time = DateTime.SpecifyKind(time, DateTimeKind.Utc);
    }
    return time.ToUniversalTime();
}

【讨论】:

  • 很有趣,但我不确定这些是否有意义。对于InputTime,来自输入的日期通常是Unspecified,因为它们是从UI 中的字符串解析而来的。对于OutputTime,这当然没有意义,因为您将时间标记为 UTC,但随后又尝试将其转换为 UTC,这将是无操作的。我不确定这些中的任何一个将如何帮助解决 OP 的问题。但是感谢您的尝试。
  • @MattJohnson - 来自 UI 的日期应该在持久层之前转换为 DateTimeKind.Local。这就是InputTime 抛出异常的原因:日期在持久化之前需要有一个已知的KindOutputTime 方法旨在直接从持久层获取日期,在几乎所有情况下(但可能不是在单元测试场景中),持久层都有未指定的 Kind。它应用 UTC 类型并以 UTC 格式返回该值(如果 time 参数恰好具有指定的 Kind,这也是返回的类型。
  • 不想开始争论,但我不得不不同意你的观点。在几乎所有情况下,DateTimeKind.Local 都是邪恶的。阅读my blog post on the subject,如果您不相信我,请参阅what Jon Skeet thought about this。它在 纯桌面 应用程序中提供了一点便利,但除此之外,它只是碍手碍脚,把事情弄得一团糟。
  • @MattJohnson - 是的,这个例子来自一个桌面应用程序。用户输入的日期被赋予 Local 类型,并在任何处理之前立即转换为 UTC。在调用ToUniversalTime 之前,我从不比较日期或进行任何其他处理,我给出的示例演示了我如何保证所有持久日期都有一个有效的Kind。实际上,这与调用DateTimeOffset.Now.UtcDateTime 并没有太大区别,但我同意传递DateTimeOffset 的实例可能比DateTime 更安全,也许这是我需要进一步研究的问题。
  • 当然,我能理解。但是仍然存在一个错误,如果类型已经是 UTC,ToUniversalTime 不会做任何事情,而SpecifyKind 不会做任何转换。因此,您的 OutputTime 函数只有在 time 参数为 Local 类型时才会执行任何操作。
猜你喜欢
  • 2013-06-20
  • 2020-02-19
  • 2017-05-30
  • 2016-02-25
  • 1970-01-01
  • 2016-10-21
  • 1970-01-01
  • 2012-11-02
  • 2015-03-17
相关资源
最近更新 更多