我的javascript应用程序必须创建事件,这些事件将作为UTC存储在数据库中,这样它们就可以在三个不同的时区中显示。
我发现很难搞清楚的是,在创建事件时,用户必须选择一个时区和日期。
其思想是:-用户从带有时区的附加下拉列表中选择日期+所需时区。-我将UTC存储在数据库中--所有用户都在3个不同的时区中查看日期。
您可能会问,为什么会有人需要这个额外的下拉列表来选择另一个时区,而在默认情况下,选择带有数据采集器的日期已经包含了一个时区。
以美国公民吉姆( Jim )为例,他一生都在利用“华盛顿时间”( EDT Washington Time)策划活动;他正在拜访中国,走进一家中国网吧,并想用这款应用策划一场活动。数据报警器将选择当地时区,即中国标准时间。但是Jim想要通过EDT进行计划,并确保应用程序能够正确地处理所有的事情。
因此,他必须具体地从一个额外的下拉列表中选择所需的时区。
所以我的问题是。由于我允许用户选择所需的时区,是否必须首先将用户输入的日期转换为该时区,然后将其转换为UTC,然后才将其存储?或者,在数据库中保存事件时,我对时区转换一点也不感兴趣吗?
因此,哪一步是正确的:-获取本地日期+选定的时区-将本地日期转换为用户选定的时区-将日期转换为UTC -存储为DB -在读取时,使用选定的时区转换为3个时区。
或者-获取本地日期+选定的时区-将日期转换为UTC,忽略时区存储到DB -当读取时,使用选定的时区在三个时区中转换。
稍后编辑-我这样做在流星,所以javascript服务器端。DB是mongodb,因此出于性能原因,必须将日期保存为JS date对象(当然,在utc中)。
第二次编辑
下面是我尝试过的实现(在输入事件日期07:00 KST时,当输出从数据库读取并在KST时区转换回来的最终结果时,只显示07:00 AM),它不起作用)
这一切都是从这里开始的--这是一个服务器端方法,它从datepicker读取日期,从时间选择器读取时间,从下拉列表读取时区:
var pStartDate = GetDateAndTimeFromPostData(eventAttributes.startDate, eventAttributes.startTime, eventAttributes.timezone);
在这里,我尝试从不同的控件(数据报警器、时间选择器、时区ddl)构建选定的日期:
function GetDateAndTimeFromPostData(dt, tm, timezone)
{
var t = tm.split(":");
var hour = t[0];
var min = t[1];
var finalDate = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate(), hour, min);
var utcConverted = ConvertUserTimezoneToServerTimezone(finalDate, timezone);
return utcConverted;
}
在这里,我尝试时区转换:
function ConvertUserTimezoneToServerTimezone(dateToConvert, tz)
{
var userTimezonedDate;
switch(tz)
{
case "EDT":
{
userTimezonedDate = moment.tz(dateToConvert, "America/New_York");
break;
}
case "CEST":
{
userTimezonedDate = moment.tz(dateToConvert, "Europe/Berlin");
break;
}
case "KST":
{
userTimezonedDate = moment.tz(dateToConvert, "Asia/Seoul");
break;
}
case "CST":
{
userTimezonedDate = moment.tz(dateToConvert, "Asia/Shanghai");
break;
}
}
var utcDateFromUserTimezonedDate = userTimezonedDate.utc().toDate();
return utcDateFromUserTimezonedDate;
}
错误已经出现在上面的代码中,因为utc的日期不是保存为KST,而是保存为GMT (我的本地时区)。
顺便提一句,我不太明白时区是如何转换的;当我访问时区网站并用chrome工具编写时:
var x = new Date();
var y = moment.tz(x, "Asia/Seoul");
y.utc().toDate()
实际上,我希望返回一个显示KST的日期对象,对吗?但它显示的是GMT+2,我的本地人。
2014年9月8日星期一23:44:05 GMT+0200 (中欧夏令时间)
我还试着向后思考这个问题,比如存储日期对象应该是什么样的,但这也让人困惑--它是否应该保存为选定的时区?例如,2014年9月8日23:44:05 GMT+0900 (KST)如果没有,我的存储日期对象应该是什么样的?
同样,我使用javascript服务器端与meteor和mongoDB作为数据库。
非常感谢,
发布于 2014-09-08 16:47:53
您提供的两个选项都不合适。
如果您想在JavaScript中完成所有这些工作,就会有在JavaScript中使用时区的几个库。但是,当后端在JavaScript中时,例如Node.js应用程序时,我建议您这样做。
使用服务器端代码,这种类型的问题通常更容易解决。您可能应该研究使用您在后端代码中使用的语言使用时区有哪些选项。
为了进一步阅读,我已经写了好几次这样的文章:
关于您的编辑--我可以就您提供的代码提供以下建议:
America/New_York
中,EDT仅用于一年的一部分,而另一部分则用于EST。虽然你有Asia/Shanghai
的CST,但它也可以申请America/Chicago
和其他几个地方。(CST有5个不同的含义。)- If you only need to handle a few time zones, you can provide a single drop down. Just use the time zone id in the value, and the full name of the time zone in text. For example:
东部时间(北美)中欧时间韩国标准时间中国标准时间
-如果你想列出世界上所有时区,你可能会发现放进一个下拉列表太长了。在这种情况下,提供两个下拉列表。第一个将选择一个国家,然后第二个将选择选定国家内的时区。由于许多国家只有一个时区,一些用户根本不必从第二个时区中作出选择。
-如果您想要一种更交互式的方法,请考虑一个基于地图的时区选择器控件,例如这一个或这一个。
GetDateAndTimeFromPostData
函数中,您要构造一个Date
对象。您需要记住,Date
对象在内部总是UTC,但是对于大多数输入和输出来说,它都是本地时区的行为。在本地,我指的是运行代码的计算机的本地。在服务器端函数中,这将是服务器的时区--在本例中是不合适的。不需要使用Date
对象,因为您已经在使用moment.js了。.tz(zone)
对象上调用moment.tz(value, zone)
与调用moment.tz(value, zone)
是有区别的。先验将时间调整为特定的时区,而后者创建了一个新的时间时刻,该时刻已经在特定的时区中被表示。- Since `x` represents the current date and time, then `moment.tz(x, "Asia/Seoul")` is just the same as `moment().tz("Asia/Seoul")`
- `y.utc()` is converting the value back to UTC, so there was no point in calling `.tz(...)` to begin with
- `.toDate()` puts everything back into a `Date` object, which represents UTC internally, but always shows its output using the local time zone.
- So in the end, you just got the current date and time as a `Date` object, so the whole thing would reduce to `new Date()`.
ISODate
类型只是存储UTC值。因此,对于需要转换为UTC的代码部分,请考虑以下内容:
moment.tz(2014,0,1,10,0,‘亚洲/首尔’).toISOString()
或者您可以直接传递等效的Date
对象--取决于您如何使用Mongo客户端:
moment.tz(2014,0,1,10,0,‘亚洲/首尔’).toDate()eventAttributes.startDate
已经是一个Date
对象,那么它可能已经转换为UTC,因此您丢失了原始输入值。您应该确保使用表示用户提供的内容的ISO字符串将该值从客户端传递到服务器。例如,传递2014-12-25T12:34:00
。不要试图在这里传递偏移量,或转换为UTC,或传递整数。除非您准确传递用户提供的内容,否则您无法存储该值。
当您将原始输入值存储在Mongo中时--将其存储为字符串。如果你把它作为一个Date
存储,那么它也会被蒙戈调整到UTC。发布于 2014-09-08 15:21:22
在JavaScript中,您可以使用UTC,也可以使用机器上的本地时间(但不知道它的时区;您最多可以确定UTC的偏移量)。
许多人试图在JS中转换时区是失败的,但由于DST、闰年/秒等原因,所有这些方法都注定要失败。
时间转换操作最好在后端完成。
您说您将日期存储在DB中,所以我假设您将其转移到某个后端。
让我们假设您的后端是一些PHP应用程序,您将从数据报警器以及时区收集纯日期作为简单字符串(例如2014-09-08 15:12:00
)。
在PHP中,您现在将执行以下操作:
$timestamp = strtotime($_POST['date']);
$dateLocal = new \DateTime("@$timestamp", new \DateTimezone($_POST['timezone']));
$dateUtc = $dateLocal->setTimezone(new \DateTimezone('UTC'));
现在,$dateUtc
将日期作为DateTime对象包含在UTC中,您现在可以进一步处理它。
顺便说一句,如果您想在执行任何其他操作之前向用户显示转换的时区,我将将其实现为某种AJAX服务。如前所述,试图转换JavaScript本身中的时区注定会失败。
https://stackoverflow.com/questions/25727304
复制相似问题