java - 如何处理在 .NET/java 中以不同方式实现的 "Local Time to UTC Conversion"

标签 java .net json datetime utc

.NET 网络服务
我有一个 .NET Web 服务,它返回 json 格式的 DateTime。 Microsoft 指定的 DateTime 的 json 表示例如:
/日期(1302847200000+0200)/
这是根据 MSDN - Stand-Alone JSON Serialization自 1970 年 1 月 1 日以来的毫秒偏移量,在 +/- 符号之前和符号之后的 UTC 本地时间到 GMT 的时区偏移量。因此,对于此序列化,DateTime 值必须从 Web 服务的本地时间转换为 UTC。

Android (java) 客户端
在接收 Web 服务结果的我的 Android 应用程序中,我使用 Gson 解析 json。因为 .NET DateTime json 序列化不是标准(根据 Microsoft 的说法,DateTime 没有这样的标准)gson 无法解析这种格式化的日期。我写了一个 Date TypeAdapter,它在客户端进行序列化和反序列化。

所以这似乎工作正常。以 UTC 格式与服务交换日期时间。如果 .NET 的 DateTime 和 Java 的日历在将本地时间转换为 UTC 时间时采用完全相同的规则,那就太好了。

一个例子:瑞士从1979年开始就有DST(夏令时)。Java知道DST之前是不存在的。 .NET 假定它从一开始就存在。因此,当 1979 年之前的夏季日期从 .NET 转换为 UTC 并从 Java 转换回本地时间(用于演示)时,该日期在同一时区会损失一个小时。

问题 如何面对这个问题?我在描述的数据交换中是否有任何错误。 我想过很多不同的解决方案。我能想象到的唯一正常工作的方法是替换 .NET json DateTime 序列化/反序列化。这当然不是一个受宠的...

感谢您的宝贵时间。

最佳答案

如果您在 Java 和 .NET 之间工作,请不要使用标准的 .NET Json 序列化程序,这会给您带来比您需要的更多的麻烦。正如您所发现的,Microsoft 使用大多数人不使用的格式。

最好的序列化器是 Newtonsoft's Json.NET ( NuGet page ) 它已成为 .NET 开发人员事实上的标准。他们有一个很棒的 DateTime 序列化/反序列化选项,使用起来很简单。 For more information check out their blog post on DateTime .我倾向于使用 ISO 8601,这是它们在 Json.NET v4.5 中的默认格式。

我曾经开发过一个企业应用程序,该应用程序通过 Json 与使用多种语言创建的许多不同产品进行通信,而 Json.NET 使产品间通信变得微不足道。

处理瑞士 DateTime 的更新

由于您要指定通用的中欧标准时间,.NET 不知道瑞士的具体日期时间规则是什么。要与瑞士打交道,您需要为 .NET 提供瑞士规则。查看 Wikipedia,它始于 1981 年,因此创建自定义 TimeZoneInfo 将类似于以下内容:

// UTC Time
var date1 = new DateTime(1969, 4, 20, 2, 20,00, DateTimeKind.Utc);
Console.WriteLine("Date 1: " + date1.ToString() + " - " + date1.IsDaylightSavingTime());

// CEST
var timezone = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
var date2 = TimeZoneInfo.ConvertTimeFromUtc(date1, timezone);
Console.WriteLine("Date 2: " + date2.ToString() + " - " + date2.IsDaylightSavingTime() + " " + timezone.IsAmbiguousTime(date2));

// Switzerland
var cesAdjRule = timezone.GetAdjustmentRules().Single();
var switzerlandStartTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(
        cesAdjRule.DaylightTransitionStart.TimeOfDay,
        cesAdjRule.DaylightTransitionStart.Month, cesAdjRule.DaylightTransitionStart.Week,
        cesAdjRule.DaylightTransitionStart.DayOfWeek
);
var switzerlandAdjustmentRule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(
    new DateTime(1981, 1, 1),
    DateTime.MaxValue.Date,
    cesAdjRule.DaylightDelta,
    switzerlandStartTransition,
    cesAdjRule.DaylightTransitionEnd
);
TimeZoneInfo.AdjustmentRule[] adjustments = {switzerlandAdjustmentRule};

var switzerlandTimeZone = TimeZoneInfo.CreateCustomTimeZone("Switzerland",
                                                            timezone.BaseUtcOffset,
                                                            "Switzerland",
                                                            "Switzerland",
                                                            "Switzerland",
                                                            adjustments, false);

var date3 = TimeZoneInfo.ConvertTimeFromUtc(date, timezone, switzerlandTimeZone);
Console.WriteLine("Date 3: " + date3.ToString() + " - " + date3.IsDaylightSavingTime() + " " + timezone.IsAmbiguousTime(date3));

它的输出看起来像这样(至少在我的机器上是这样):

Date 1: 4/20/1969 2:20:00 AM - False
Date 2: 4/20/1969 4:20:00 AM - True - False
Date 3: 4/20/1969 3:20:00 AM - True - False

如您所见,IsDaylightSavingsTime 在 DateTime 上为 True,但 TimeZoneInfo 正确转换了我们的时间。尝试其他一些组合看起来也不错。您还可以使用 TimeZoneInfo.CovertTime() 在它认为您拥有的 CEST 和瑞士之间进行转换。

关于java - 如何处理在 .NET/java 中以不同方式实现的 "Local Time to UTC Conversion",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10247656/

相关文章:

java - 如何在 Package Explorer 中显示更少的项目?

java - 带水印的阻塞队列

c# - 服务器不接受在 HttpClientHandler 上设置的证书

c# - .NET 富文本框中的彩色文本

javascript - Node.js 从 csv/JSON 过滤/提取数据子集

java - WAR 文件外部的库依赖项

java - 使用 mybatis 保存/更新集合,常见的做法是什么?

c# - Process.从用户机器开始

ios - 使用 NSURLConnection 在同一请求中发送 JSON 和查询参数

javascript - 解析/操作格式奇怪的 json 数组