首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何从用户日期和时区输入正确地将UTC日期存储在数据库中?

如何从用户日期和时区输入正确地将UTC日期存储在数据库中?
EN

Stack Overflow用户
提问于 2014-09-08 15:03:14
回答 2查看 4.8K关注 0票数 4

我的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读取日期,从时间选择器读取时间,从下拉列表读取时区:

代码语言:javascript
运行
复制
var pStartDate = GetDateAndTimeFromPostData(eventAttributes.startDate, eventAttributes.startTime, eventAttributes.timezone);

在这里,我尝试从不同的控件(数据报警器、时间选择器、时区ddl)构建选定的日期:

代码语言:javascript
运行
复制
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;
    }

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

代码语言:javascript
运行
复制
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工具编写时:

代码语言:javascript
运行
复制
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作为数据库。

非常感谢,

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-09-08 16:47:53

您提供的两个选项都不合适。

  • 如果您允许用户在美国东部时间安排事件,那么他将进入该时区的时间。他现在在中国这一事实是无关紧要的。所以从他当地的中国标准时间转换到UTC并不是你想要做的事情。
  • 由于您正在存储未来的事件,所以只存储UTC值并不是最好的建议。您应该存储原始输入的值和原始选定的时区。您也可以存储UTC时间,但是您应该随时准备重新计算它。 这一点很重要,因为时区规则在输入事件的时间和事件的实际时间之间可能发生更改。例如,用户可能不是在美国,而是在俄罗斯。今年(2014年)将发生变化,并且需要对时区数据进行更新。如果在应用数据更新之前对事件进行了调度,则将使用旧规则计算UTC值。如果事件发生在此更改之后(例如,2014年11月),则一旦应用更新,事件时间将错误地更改。

如果您想在JavaScript中完成所有这些工作,就会有在JavaScript中使用时区的几个库。但是,当后端在JavaScript中时,例如Node.js应用程序时,我建议您这样做。

使用服务器端代码,这种类型的问题通常更容易解决。您可能应该研究使用您在后端代码中使用的语言使用时区有哪些选项。

为了进一步阅读,我已经写了好几次这样的文章:

关于您的编辑--我可以就您提供的代码提供以下建议:

  • 永远不要试图将时区缩写映射到特定的时区。正如您可以请参阅维基百科上的列表所做的那样,有太多的歧义。即使在你自己列出的4个时区中,也有一些问题。具体来说,在America/New_York中,EDT仅用于一年的一部分,而另一部分则用于EST。虽然你有Asia/Shanghai的CST,但它也可以申请America/Chicago和其他几个地方。(CST有5个不同的含义。)
  • 与时区缩写的下拉列表不同,还有几个其他选项:
代码语言:javascript
运行
复制
- 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)是有区别的。先验将时间调整为特定的时区,而后者创建了一个新的时间时刻,该时刻已经在特定的时区中被表示。
  • 关于你的侧记,你正在挫败瞬间时区的目的:
代码语言:javascript
运行
复制
- 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()`.

  • 关于MongoDB,它的ISODate类型只是存储UTC值。因此,对于需要转换为UTC的代码部分,请考虑以下内容: moment.tz(2014,0,1,10,0,‘亚洲/首尔’).toISOString() 或者您可以直接传递等效的Date对象--取决于您如何使用Mongo客户端: moment.tz(2014,0,1,10,0,‘亚洲/首尔’).toDate()
  • 尽管我在最初的答复中说了些什么,但一定要考虑一下。UTC值将帮助您及时知道偶数应该运行的时间,但是您不应该忘记原始的输入值!如果eventAttributes.startDate已经是一个Date对象,那么它可能已经转换为UTC,因此您丢失了原始输入值。您应该确保使用表示用户提供的内容的ISO字符串将该值从客户端传递到服务器。例如,传递2014-12-25T12:34:00。不要试图在这里传递偏移量,或转换为UTC,或传递整数。除非您准确传递用户提供的内容,否则您无法存储该值。 当您将原始输入值存储在Mongo中时--将其存储为字符串。如果你把它作为一个Date存储,那么它也会被蒙戈调整到UTC。
票数 6
EN

Stack Overflow用户

发布于 2014-09-08 15:21:22

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

许多人试图在JS中转换时区是失败的,但由于DST、闰年/秒等原因,所有这些方法都注定要失败。

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

您说您将日期存储在DB中,所以我假设您将其转移到某个后端。

让我们假设您的后端是一些PHP应用程序,您将从数据报警器以及时区收集纯日期作为简单字符串(例如2014-09-08 15:12:00)。

在PHP中,您现在将执行以下操作:

代码语言:javascript
运行
复制
$timestamp = strtotime($_POST['date']);
$dateLocal = new \DateTime("@$timestamp", new \DateTimezone($_POST['timezone']));
$dateUtc = $dateLocal->setTimezone(new \DateTimezone('UTC'));

现在,$dateUtc将日期作为DateTime对象包含在UTC中,您现在可以进一步处理它。

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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25727304

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档