Javascript 如何根据用户日期和时区输入在数据库中正确存储UTC日期?

Javascript 如何根据用户日期和时区输入在数据库中正确存储UTC日期?,javascript,datetime,timezone,Javascript,Datetime,Timezone,我的javascript应用程序必须创建事件,这些事件将作为UTC存储在数据库中,以便以后可以在3个不同的时区中显示 我发现很难弄清楚的棘手部分是,在创建事件时,用户必须选择一个时区和日期 这个想法是: -用户从带有时区的附加下拉列表中选择日期+所需时区。 -我在数据库中存储为UTC -所有用户都可以在3个不同的时区中看到日期 您可能会问,当使用日期选择器选择默认已包含时区的日期时,为什么任何人都需要额外的dropdownlist来选择另一个时区 例子:吉姆,美国公民,他用美国东部时间华盛顿时间

我的javascript应用程序必须创建事件,这些事件将作为UTC存储在数据库中,以便以后可以在3个不同的时区中显示

我发现很难弄清楚的棘手部分是,在创建事件时,用户必须选择一个时区和日期

这个想法是: -用户从带有时区的附加下拉列表中选择日期+所需时区。 -我在数据库中存储为UTC -所有用户都可以在3个不同的时区中看到日期

您可能会问,当使用日期选择器选择默认已包含时区的日期时,为什么任何人都需要额外的dropdownlist来选择另一个时区

例子:吉姆,美国公民,他用美国东部时间华盛顿时间计划了一生的活动;他正在中国访问,进入一家中国网吧,并希望使用该应用程序计划一项活动。日期选择器将选择当地时区,即中国标准时间。但是Jim希望通过EDT进行计划,并确保应用程序能够正确处理所有事情

因此,他必须特别从一个附加的下拉列表中选择所需的时区

所以我的问题是。 因为我允许用户选择所需的时区,所以我是否必须先将用户输入的日期转换为该时区,然后再将其转换为UTC,然后再存储? 或者在数据库中保存事件时,我对时区转换一点也不感兴趣

那么哪一步是正确的: -获取本地日期+所选时区 -将本地日期转换为用户选择的时区 -将日期转换为UTC -存储到数据库 -读取时,使用所选时区在3个时区中进行转换

或 -获取本地日期+所选时区 -将日期转换为UTC,忽略时区 -存储到数据库 -读取时,使用所选时区在3个时区中进行转换


稍后编辑-我在meteor中执行此操作,所以javascript服务器端。DB是mongodb,因此出于性能原因,日期必须保存为JS日期对象(当然是utc)


第二版

下面是我尝试过的实现(当我输入事件日期为07:00 AM KST时,当输出从数据库读回并在该KST时区转换回的最终结果时,它不起作用,显示的不是07:00 AM)

这一切都从这里开始-这是一个服务器端方法,它从日期选择器读取日期,从时间选择器读取时间,从下拉列表读取时区:

var pStartDate = GetDateAndTimeFromPostData(eventAttributes.startDate, eventAttributes.startTime, eventAttributes.timezone);
在这里,我尝试从不同的控件(datepicker、timepicker、timezone ddl)构建所选日期:

在这里,我尝试时区转换:

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,我的本地tz

2014年9月8日星期一23:44:05 GMT+0200(中欧昼时)

我也试着反向思考,比如存储的日期对象应该是什么样子,但这也让人困惑——它应该保存为选定的时区吗?e、 g.2014年9月8日星期一23:44:05 GMT+0900(KST)如果没有,我存储的日期对象必须是什么样子

同样,我使用javascript服务器端,meteor和mongoDB作为数据库

非常感谢,

在JavaScript中,您可以使用UTC,也可以使用机器上的本地时间(但不知道其时区;您最多可以确定UTC的偏移量)

许多人在JS中转换时区的尝试失败了,但所有这些方法都注定要失败,因为DST、闰年/秒等。有太多的陷阱使得实现极其复杂

时间转换操作最好在后端完成

您说您将日期存储在数据库中,因此我假设您正在将其传输到某个后端

让我们假设您的后端是某个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
包含UTC中坚如磐石的日期时间对象,您现在可以进一步处理该对象


顺便说一句,如果您想在做任何其他事情之前向用户显示转换后的时区,我会将其实现为某种AJAX服务。如前所述,试图在JavaScript中转换时区注定要失败。

您提供的两个选择都不合适

  • 如果您允许用户在美国东部时间安排活动,则他将输入该时区的时间。他目前在中国这一事实无关紧要。因此,将其当地的中国标准时间转换为UTC不是您想要做的事情

  • 由于要存储将来的事件,因此仅存储UTC值不是最好的建议。您应该存储原始输入值和原始选定时区。您也可以存储UTC时间,但应随时准备重新计算UTC时间

    这一点很重要,因为时区规则可能在输入事件的时间和事件的实际时间之间发生变化。例如,用户可能不是在美国,而是在俄罗斯,并且需要更新您的时区数据。如果事件是在应用数据更新之前安排的,则您将使用旧规则计算UTC值。如果事件在此更改之后发生(例如,2014年11月),则一旦应用更新,事件时间将错误地更改

如果您想在JavaScript中完成这一切,有以下几种方法。但是,我建议主要在后端使用JavaScript时使用这种方法,例如使用Node。
$timestamp = strtotime($_POST['date']);
$dateLocal = new \DateTime("@$timestamp", new \DateTimezone($_POST['timezone']));
$dateUtc = $dateLocal->setTimezone(new \DateTimezone('UTC'));
<select name="tz">
    <option value="America/New_York">Eastern Time (North America)</option>
    <option value="Europe/Berlin">Central European Time</option>
    <option value="Asia/Seoul">Korean Standard Time</option>
    <option value="Asia/Shanghai">China Standard Time</option>
</select>
moment.tz([2014,0,1,10,0],'Asia/Seoul').toISOString()
moment.tz([2014,0,1,10,0],'Asia/Seoul').toDate()