首页 > 解决方案 > 有没有办法将 .Net TimeZoneInfo 转换为 Java ZonedDateTime?

问题描述

这是这个问题的后续。我正在构建一个 RESTful 服务器(使用 C#,但核心引擎是 Java(通过 IKVM))。我们正在用 C# Java 等编写客户端。

因此,对于 C# 客户端的特定情况,如果他们想要在服务器端使用 ZonedDateTime,我需要传递一个类似于“2018-10-21T08:11:55-06:00[America/Denver]”的字符串。对于这种情况,我认为我应该让他们传递给我一个 (DateTime, TimeZoneInfo) 并从中构建字符串。

为此,我需要从 TimeZoneInfo 的设置中获取 Java“America/Denver”。有什么办法可以实现这种转换。

据我了解,没有 ISO 或其他广泛使用的设置来唯一标识时区。

标签: c#datetimetimezonezoneddatetime

解决方案


“America/Denver”是该时区的 IANA 名称。时区数据库 (tzdb)包含这些名称及其规则(可能随时间而变化)。NodaTime 使用 tzdb 数据来执行其逻辑。

您可以使用TimeZoneConverter包将 a 转换TimeZoneInfo为 tzdb 时区 ID。

你已经问了一些与此相关的问题,我想在这里为你拼凑一些。

NodaTime 一路向下

如果这样做是可行的,你应该让消费者给你一个ZonedDateTime. 它是一个包含基于 Java 的核心引擎所需的所有信息的单一值,这正是您所要求的(此处)。使用已在域中验证的单个值(而不是用于组成部分的自定义容器)将容易出错的活动推迟到消费者身上,消费者比您更适合解决它们,并且必须在致电您的客户之前完成。然后,您不必为与您不应该关心的事情相关的任何错误或错误负责。

如果您有一个ZonedDateTime实例,那么您现在需要的只是一个自定义模式,该模式将为您提供 Java 端期望格式的字符串。

ZonedDateTimePattern customPattern = ZonedDateTimePattern.Create(
    "uuuu'-'MM'-'dd'T'HH':'mm':'sso<Z-HH':'mm>'['z']'",
    CultureInfo.InvariantCulture,
    mapping => mapping.LocalDateTime.InZoneLeniently(mapping.Zone),
    DateTimeZoneProviders.Tzdb,
    default);

根据您之前的问题,您似乎需要一个文字“ Z”来表示 UTC 而不是“ +00:00”。" Z-HH':'mm" 子模式就是这样做的。如果您需要不同的东西,请查看偏移模式文档。

现在您可以使用customPattern来创建您需要发送的字符串。

string formatted = customPattern.Format(zonedDateTime);

ZonedDateTime如有必要,可以使用相同的模式将这样的字符串解析回。

仅在内部使用 NodaTime

如果您不能期望消费者使用 NodaTime 类型,那没关系。接收DateTimeOffsetTimeZoneInfo 也可以工作。您可以将它们转换为ZonedDateTime您的客户内部的一个,而无需太多仪式。

// Given: DateTimeOffset dateTimeOffset, TimeZoneInfo timeZoneInfo

DateTimeZone dateTimeZone = DateTimeZoneProviders.Tzdb[TZConvert.WindowsToIana(timeZoneInfo.Id)];

ZonedDateTime zonedDateTime = OffsetDateTime.FromDateTimeOffset(dateTimeOffset).InZone(dateTimeZone);

这样做的潜在问题是集体输入尚未在域中得到验证。 Matt Johnson-Pint 在他的回答中指出,可以传递一个偏移量,这对于提供的时区是不正确的。准备好添加验证或尝试/捕获,这样您就可以用非常清晰的语言告诉消费者他们做错了什么。

接受模棱两可的时代

可以接受,DateTime但您将被迫对您和/或消费者可能无法接受的模棱两可的时间做出假设。然后,您将负责与您的 API 功能无关的逻辑。

为了完整起见,我将其包括在此处,但这不是任何形式的认可。

// Given: DateTime dateTime, TimeZoneInfo timeZoneInfo

DateTimeZone dateTimeZone = DateTimeZoneProviders.Tzdb[TZConvert.WindowsToIana(timeZoneInfo.Id)];

ZonedDateTime zonedDateTime = LocalDateTime.FromDateTime(dateTime).InZoneLeniently(dateTimeZone);

InZoneLeniently是那里的大红旗。当遇到一个模棱两可的时候它会“做它”,它可能是不正确的。请记住,“just”是一个 4 个字母的单词。


推荐阅读