你如何保存从浏览器到服务器的 JavaScript 日期的时区,然后返回?

Posted

技术标签:

【中文标题】你如何保存从浏览器到服务器的 JavaScript 日期的时区,然后返回?【英文标题】:How do you preserve a JavaScript date's time zone from browser to server, and back? 【发布时间】:2018-11-30 11:19:49 【问题描述】:

例如,使用日期和时间控件,用户选择日期和时间,使得字符串表示如下:

"6-25-2012 12:00:00 PM"

这个用户恰好在 EST 时区。该字符串被传递到服务器,服务器将其转换为 .NET DateTime 对象,然后将其存储在 SQL Server 中的 datetime 列中。

当稍后将日期返回给浏览器时,需要将其转换回日期,但是当将上述字符串输入日期时,它会损失 4 小时的时间。我相信这是因为在创建 javascript 日期时未指定时区时,它默认为本地时间,并且由于 EST 是格林威治标准时间的 -400,它会从下午 12 点减去 4 小时,即使下午 12 点本应指定为 EST 时用户在 EST 时区的机器上选择了它。

显然需要在原始日期时间字符串中添加一些内容,然后才能将其传递给服务器以进行持久化。这样做的推荐方法是什么?

【问题讨论】:

您可能更愿意将日期处理为秒数 d.getTime() / 1000 可以很容易地使用大多数语言转换回日期。 好的,但是如果原始日期是由字符串部分构造的(两个不同的控件,一个来自日期选择器,另一个来自时间选择器),那么我该如何告诉 JavaScript 日期我构造它所在的时区,否则 d.getTime() / 1000 将根据我给它的时间完成,减去 4 小时。 您是否使用不同的时区运行测试以确保问题来自那里而不是来自转换? 数据库中的日期时间存储为日期时间,查询时 SQL 中的表示是 exactly 正如我在上面的示例中所示,这意味着有不是翻译问题。当它返回给客户端时,我什至可以在浏览器调试器中看到它。但是当它被输入到 JavaScript 日期对象时,它会损失 4 个小时。这是因为没有指定时区,所以问题是,如何为最初创建的日期指定时区? 相关 - Should the Server or the Client handle timezone when sending/receiving dates? 【参考方案1】:

不要依赖 JavaScript 的 Date 构造函数来解析字符串。行为和支持的格式因浏览器和语言环境而异。如果您直接使用Date 对象,Here 只是一些默认行为。

如果您必须来自字符串,请尝试使用标准化格式,例如 ISO8601。您以该格式提供的日期为"2012-06-25T12:00:00"。在 JavaScript 中使用这些最简单的方法是使用 moment.js。

另外,请注意您实际要表达的意思。现在,您正在传递本地日期/时间,保存本地/日期/时间,并返回本地日期/时间。在此过程中,“本地”的概念可能会发生变化。

在许多情况下,日期/时间旨在表示一个准确的时刻。要使该工作正常进行,您需要在客户端将输入的本地时间转换为 UTC。将 UTC 发送到您的服务器并存储它。稍后,检索 UTC 并将其发送回您的客户端,将其作为 UTC 处理并转换回本地时间。您可以使用 moment.js 轻松完成所有这些工作:

// I'll assume these are the inputs you have.  Adjust accordingly.
var dateString = "6-25-2012";
var timeString = "12:00:00 PM";

// Construct a moment in the default local time zone, using a specific format.
var m = moment(dateString + " " + timeString, "M-D-YYYY h:mm:ss A");

// Get the value in UTC as an ISO8601 formatted string
var utc = m.toISOString(); // output: "2012-06-25T19:00:00.000Z"

在.Net的服务器上:

var dt = DateTime.Parse("2012-06-25T19:00:00.000Z",   // from the input variable
                        CultureInfo.InvariantCulture, // recommended for ISO
                        DateTimeStyles.RoundtripKind) // honor the Z for UTC kind

将其存储在数据库中。稍后将其检索并发送回:

// when you pull it from your database, set it to UTC kind
var dt = DateTime.SpecifyKind((DateTime)reader["yourfield"], DateTimeKind.Utc);

// send it back in ISO format:
var s = dt.ToString("o"); // "o" is the ISO8601 "round-trip" pattern.

将它传回moment.js中的javascript:

// construct a moment:
var m = moment("2012-06-25T19:00:00.000Z"); // use the value from the server

// display it in this user's local time zone, in whatever format you want
var s = m.format("LLL");   // "June 25 2012 12:00 PM"

// or if you need a Date object
var dt = m.toDate();

看 - 这很容易,而且您不需要对时区进行任何花哨的操作。

【讨论】:

要将该 ISO 字符串存储在数据库中,该列是否必须是 datetimeoffset 字段(相对于 datetime SQL 字段)?当然,假设我们不只是存储一个字符串。还是最好只存储字符串? 不,不要存储字符串。如果要存储 UTC,则可以使用 datetime 或 datetime2。对于这种特定情况,您不需要 datetimeoffset。您可以使用它,但除非您关心用户的本地时区,否则您可能不需要这样做。在DateTime vs DateTimeOffset 上查看我的回答。 只是为了补充我之前的评论 - 许多人实际上更喜欢使用 DateTimeOffset 表示 UTC。即使他们知道偏移量始终为零,但在 DateTimeOffset 而不是 DateTime 中跟踪它是防止它意外被错误解释的好方法。唯一的缺点是它将使用+00:00 而不是Z 进行序列化,但这通常是可以接受的。【参考方案2】:

在这里,我认为这就是您要寻找的: How to ignore user's time zone and force Date() use specific time zone

在我看来你可以这样做:

var date = new Date("6-25-2012 12:00:00 PM");

var offset = date.getTimezoneOffset(); // returns offset from GMT in minutes

// to convert the minutes to milliseconds
offset *= 60000;

// the js primitive value is unix time in milliseconds so this retrieves the 
// unix time in milliseconds and adds our offset.
// Now we can put this all back in a date object
date = new Date(date.valueOf() + offset);

// to get back your sting you can maybe now do something like this:
var dateString = date.toLocaleString().replace(/\//g,'-').replace(',','');

【讨论】:

【参考方案3】:

责备 JSON.Stringfy()... 并执行以下操作:

x = (your_date);
x.setHours(x.getHours() - x.getTimezoneOffset() / 60);

【讨论】:

这是我见过的最好的 hack 来保留日期字符串 tz haha​​。但是如果字符串中不存在时区,它将不起作用,例如:“2020-12-23T22:02:30”【参考方案4】:

我在将日期发送到服务器之前使用了过滤器:

vm.dateFormat = 'yyyy-MM-dd';
dateToSendToServer = $filter('date')(dateFromTheJavaScript, vm.dateFormat);

【讨论】:

以上是关于你如何保存从浏览器到服务器的 JavaScript 日期的时区,然后返回?的主要内容,如果未能解决你的问题,请参考以下文章

js如何保存文件

将号码数据保存到本地存储

如何在浏览器的调试器编辑javascript文件并保存

如何禁止使用Javascript保存密码泡沫铬?

如何将FTP从网页模式转化成文件夹模式

js用ajax从服务端获取了json数据,怎么保存到指定的本地目录啊