.NET 日期、时刻.js、UTC 和时区转换



>我通过Ajax调用获得了UTC日期,例如"/Date(1517216466000+0100)/"
即打印到控制台时:Mon Jan 29 2018 10:01:06 GMT+0100 (W. Europe Standard Time)

我需要做的是让用户更改时区:我可以轻松地做到这一点,例如moment(myDate).tz("Japan").

然后我需要以 UTC 格式保存日期,但我无法做到这一点.
我一直在试验moment.utc(),但对于上面的输入,它返回的时间少了 1 小时

如何处理这种情况?总结:
1. 从网络服务获取 UTC 时间
2.让用户更改时区
3.以 UTC 格式保存修改日期(不带时区)
工作演示:https://stackblitz.com/edit/angular-kqrct7?file=app%2Fapp.component.html

编辑澄清:
让我们看看小时。我从WCF得到的日期是10点钟。浏览器将其解释为 10 点钟,但在 GMT+1 中,因此当我将其转换为 UTC 时,它变为 9 点钟。
我希望它是10 点作为 UTC。然后,如果我修改时区,例如这个日期的分钟,我希望能够获得这个日期的UTC值。

编辑2:使我的问题更简单,以便澄清

  1. 有一个 UTC 日期,我从网络服务中获得,例如:"/Date(1517216466000+0100)/",即:2018 年 1 月 29 日星期一 10:01:06 GMT+0100(欧洲标准时间)打印到控制台时。

  2. 我用moment(this.inputDate).tz("Europe/Berlin").format()添加一个时区,但它保持10:01:06,我想是因为我的浏览器GMT + 1。

  3. 我希望将原始字符串用作 UTC 日期,并且它应该保持 10:01:06,而不是您在上面看到的 09:01:06(第 2 时刻示例),因此时区"欧洲/柏林"将是 11:01:6

在 .NET JSON 格式的日期"/Date(1517216466000+0100)/"中,可以忽略时区偏移量。它表示"2018-01-29T09:01:06.000Z",其中源系统的时区偏移量为 +0100。因此,如果您不关心源时区,请忽略它。

这也是与 2018 年 1 月 29 日星期一 10:01:06 GMT+0100(欧洲标准时间)相同的时刻,只是偏移量不同。

UTC不是一种格式,而是一种时间标准。如果要使用 ISO 8601 格式:

  1. 提取第一个数值
  2. 转换为数字
  3. 传递给日期构造函数
  4. 在生成的日期上调用toISOString方法

var s = '/Date(-1517216466000+0100)/';
console.log(new Date(+s.replace(/^[^d-]+(-?d+).*$/,'$1')).toISOString());

您还可以使用 moment.js 对其进行解析和格式化,根据文档,它可以处理 .NET JSON 格式,而无需指定格式。因此,您可以这样做,也可以提取时间值并使用"x"格式令牌对其进行解析:

var s = '/Date(1517216466000+0100)/';
// Let moment.js guess the format
console.log(moment(s).utc());
// Extract time value and supply format
console.log(moment(s.replace(/^[^d-]+(-?d+).*$/,'$1'), 'x').utc());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>

"/Date(1517216466000+0100)/"是序列化日期/时间的非标准方法。看看ISO8601它定义了几种表示日期和时间的标准方法。

话虽如此,让我们来看看这被评估为什么......

moment("/Date(1517216466000+0100)/").toDate()

为我提供Mon Jan 29 2018 09:01:06 GMT+0000 (GMT Standard Time)(在英国)

仅获取时间戳值1517216466000

new Date(1517216466000)

也给Mon Jan 29 2018 09:01:06 GMT+0000 (GMT Standard Time)

这意味着+0100将被忽略。

您实际上并没有修改时间,那么为什么您希望它保存为Mon Jan 29 2018 09:01:06以外的任何东西

更新

但是"原始"字符串表示Mon Jan 29 2018 09:01:06 UTC忽略+0100,并且您对 UTC 的偏移量也+0100只是巧合。一个关闭。

偏移量和时区是两个不同的东西。时区包括 UTC 的偏移量以及夏令时何时/是否生效。仅仅因为它说 +0100 并不一定意味着(W. 欧洲标准时间),因为它很容易(西非时间),它也是 UTC+0100,但根本不遵守夏令时。

您拥有的时间"/Date(1517216466000+0100)/"并不能传达足够的信息来说明它是哪个时区,JS/moment 仅使用时间戳1517216466000,因此使用 UTC。当您console.log()此选项时,浏览器会将其作为本地时间写入屏幕Mon Jan 29 2018 10:01:06 GMT+0100 (W. Europe Standard Time)但这仅是基础日期时间的表示形式。

通过告诉时刻使用特定时区,它只是改变了日期/时间的显示方式,实际上并没有改变它所代表的时间。

如果使用日期选取器更改日期/时间,则必须以适当的方式序列化要发送到后端的值,以便无法更改的 .Net 应用能够理解并传达你的意图。

  1. 从服务器获取日期作为var serverTime = "/Date(1517216466000+0100)/"
  2. 使用时刻var time = new moment(serverTime)将其转换为 JS 日期
  3. 让用户指定时区,即日本标准时间 (UTC+9)time = time.tz("Japan")
  4. time仍然代表Mon Jan 29 2018 09:01:06 UTC但是当与time.format()一起显示在屏幕上时,会给出"2018-01-29T18:01:06+09:00"

你说"我希望它是 10 点作为 UTC"。不幸的是,您的值不是10 点钟 UTC,也永远不会是 10 点钟 UTC,因为它不是。现在是世界协调时 9 点钟

您可以自己解析从服务器获得的值,但来自服务器的时间UTC 上午 9 点。如果将其更改为 UTC 上午 10 点,那么您会看到当地时间Mon Jan 29 2018 11:01:06 GMT+0100 (W. Europe Standard Time)点 - 11 点。

感谢大家的详细回答,他们对我理解我的问题有很大帮助!但是,正确的解决方案如下:

数据库中的 10 点钟是 UTC 时间,在 Moment 中被解释为 9 点 UTC.js因为 C# 将其作为本地时间处理。因此,在将日期发送给客户端之前,我必须指出它是UTC:

var utcToClient = DateTime.SpecifyKind(downtime.DownTimeStartUTC, DateTimeKind.Utc)

然后,在 Moment 中,我可以创建一个 UTC:

var jsUtc = moment.utc(downtime.DownTimeStartUTC)

更改时区轻而易举:

jsUtc.tz(userSelectedTimezone)

并将日期保存在数据库中,我在 C# 中使用了这个:

var utcFromClient = Record.DownTimeStartUTC.ToUniversalTime()

最新更新