>我通过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:使我的问题更简单,以便澄清
有一个 UTC 日期,我从网络服务中获得,例如:"/Date(1517216466000+0100)/",即:2018 年 1 月 29 日星期一 10:01:06 GMT+0100(欧洲标准时间)打印到控制台时。
我用moment(this.inputDate).tz("Europe/Berlin").format()添加一个时区,但它保持10:01:06,我想是因为我的浏览器GMT + 1。
我希望将原始字符串用作 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 格式:
- 提取第一个数值
- 转换为数字
- 传递给日期构造函数
- 在生成的日期上调用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 应用能够理解并传达你的意图。
例
- 从服务器获取日期作为
var serverTime = "/Date(1517216466000+0100)/"
- 使用时刻
var time = new moment(serverTime)
将其转换为 JS 日期 - 让用户指定时区,即日本标准时间 (UTC+9)
time = time.tz("Japan")
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()