TL;DR:
- 服务器端继续使用Noda Time
- 选择是使用BCL数据还是IANA数据;我个人会推荐 IANA,但这由您决定。 (除此之外,IANA 数据的版本更加清晰。)
- 使用 Noda Time 生成 moment.js 数据,以便您了解exactly客户端将使用什么,并且它将与您在服务器上所做的保持一致
- 针对数据变化时发生的情况制定策略
Details:
有时需要在服务器端(C#)和客户端(JS)精确转换 TZ。
你需要得到exactly双方时区数据相同and双方的等效实现。这有问题,因为:
- IANA 时区数据会定期更新(因此您需要能够说“使用数据 2015a”)
- Windows时区数据定期更新
- 我不敢打赌 IANA 规则的每次实施都完全相同,尽管它们应该是相同的
- I know那
TimeZoneInfo
随着时间的推移,实施方式发生了变化,部分是为了删除一些odd bugs并部分地包含更多数据。 (.NET 4.6 理解时区改变其历史标准偏移量的概念;早期版本不理解)
使用 Noda Time,您可以非常轻松地将 BCL 或 IANA 时区数据转换为 moment.js 格式 - 并且比 Evgenyt 的代码更可靠,因为TimeZoneInfo
不允许您请求转换。 (由于错误TimeZoneInfo
本身,有一些小口袋,偏移量可以在几个小时内改变 - 它们不应该改变,但如果你想匹配TimeZoneInfo
行为准确,你需要能够找到所有这些 - Evgenyt 的代码并不总是能发现这些。)即使 Noda Time 不镜像TimeZoneInfo
准确地说,它应该符合itself.
moment.js 格式看起来非常简单,因此只要您不介意将数据传送到客户端,这绝对是一个选择。不过,您需要考虑当数据发生变化时该怎么办:
- 如何在服务器上获取它?
- 您如何应对客户端暂时使用旧数据的情况?
如果精确的一致性对您来说确实很重要,您可能希望将时区数据与时区数据版本一起发送到客户端......然后客户端可以在发布数据时将其返回给服务器。 (当然,我假设它正在这样做。)然后服务器可以使用该版本,或者拒绝客户端的请求并说有更新的数据。
下面是一些将 Noda 时区数据转换为 moment.js 的示例代码 - 对我来说看起来不错,但我还没有用它做太多事情。它与 momentjs.com 中的文档匹配...请注意,必须反转偏移量,因为 moment.js 决定使用positive时区的偏移量是behindUTC,出于某种原因。
using System;
using System.Linq;
using NodaTime;
using Newtonsoft.Json;
class Test
{
static void Main(string[] args)
{
Console.WriteLine(GenerateMomentJsZoneData("Europe/London", 2010, 2020));
}
static string GenerateMomentJsZoneData(string tzdbId, int fromYear, int toYear)
{
var intervals = DateTimeZoneProviders
.Tzdb[tzdbId]
.GetZoneIntervals(Instant.FromUtc(fromYear, 1, 1, 0, 0),
Instant.FromUtc(toYear + 1, 1, 1, 0, 0))
.ToList();
var abbrs = intervals.Select(interval => interval.Name);
var untils = intervals.Select(interval => interval.End.Ticks / NodaConstants.TicksPerMillisecond);
var offsets = intervals.Select(interval => -interval.WallOffset.Ticks / NodaConstants.TicksPerMinute);
var result = new { name = tzdbId, abbrs, untils, offsets };
return JsonConvert.SerializeObject(result);
}
}