【问题标题】:.NET date, Moment.js, UTC and Timezone shifting.NET 日期、Moment.js、UTC 和时区转换
【发布时间】:2018-07-08 04:50:49
【问题描述】:

我通过 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 值。

EDIT2:让我的问题更容易澄清

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

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

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

【问题讨论】:

  • 您能否使用实际示例值来解释您的问题并说明问题所在。
  • Save the modified date in UTC (without the timezone) UTC 没有时区,这就是重点。 :)
  • @Keith 描述已更新
  • @phuzi 添加了更多详细信息
  • 你能用简单的术语解释一下你想要做什么吗..? Javascript 中的日期/时间可能会有点令人困惑,并且您最终可能会在不需要时将事情复杂化。基本上,Javascript 中的所有日期时间都在语言环境时间中视觉上工作,但在内部工作在 UTC,这样想可能会有所帮助。

标签: javascript date datetime momentjs


【解决方案1】:

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

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

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

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

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

您也可以使用moment.js 对其进行解析和格式化,根据the documentation 可以处理.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>

【讨论】:

  • 在我看来 Moment 支持这种格式:momentjs.com/docs/#/parsing/asp-net-json-date
  • 偏移量包含在序列化值中,因为 .NET DateTime.KindUnspecified,序列化就像是 Local。或者,如果您将其种类设置为Utc,它将被序列化为'/Date(-1517216466000)/',这表明它是.Net 中的UTC 值。
【解决方案2】:

"/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 并不一定意味着(西欧洲标准时间),因为它可能很容易是(西非时间),它也是 UTC+0100,但根本不遵守夏令时。

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

通过告诉 moment 使用特定的时区,它只会改变日期/时间的显示方式,并不会真正改变它所代表的时间。

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

示例

  1. 从服务器获取日期为var serverTime = "/Date(1517216466000+0100)/"
  2. 使用 moment 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”。不幸的是,您的值是 NOT 10 点 UTC 并且永远不会是 10 点 UTC,因为它不是。 世界标准时间 9 点

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

【讨论】:

  • 我确实修改了时间,使用 Material Datepicker 和一个用于时区转换的下拉菜单,我只是将它从我的示例中删除以使其更简单。
  • 其次,很遗憾我无法更改字符串时间格式,因为它是旧的 .NET 应用程序的一部分。
  • @flow3r “旧 .NET 应用程序的一部分。”认为这样。如果保存回来的值不正确,那么包含您正在执行的操作的代码/示例可能是一个好主意,这样我们就可以看到问题出在哪里。
  • 感谢您的详细回答,但我想,我们可能会谈论一些不同的事情。数据库中有一个 Oracle 日期,据说是 UTC。那是 10 点,在数据库中,但是当我尝试在客户端解析它时,它变成了当地时间 10 点。这是我要避免的。
  • 如果数据库中的时间是 10 点 UTC,那么听起来 .Net 应用程序在处理 DateTimes 的方式上存在问题。您能否确认日期实际上以 UTC 格式存储在数据库中?看起来它正在将其视为当地时间
【解决方案3】:

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

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

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

然后,我可以立即创建一个 UTC:

var jsUtc = moment.utc(downtime.DownTimeStartUTC)

更改时区轻而易举:

jsUtc.tz(userSelectedTimezone)

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

var utcFromClient = Record.DownTimeStartUTC.ToUniversalTime()

【讨论】:

    猜你喜欢
    • 2023-01-14
    • 2014-06-11
    • 2014-11-17
    • 1970-01-01
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-26
    相关资源
    最近更新 更多