假设您网站的用户输入了一个日期范围。

2009-1-1 to 2009-1-3

您需要将此日期发送到服务器进行某些处理,但服务器要求所有日期和时间均为UTC。

现在假设用户在阿拉斯加。由于它们所处的时区与UTC完全不同,因此需要将日期范围转换为如下所示:

2009-1-1T8:00:00 to 2009-1-4T7:59:59

使用JavaScriptDate对象,如何将第一个“本地化”日期范围转换为服务器能够理解的内容?


当前回答

该方法将为您提供:2017-08-04T11:15:00.000+04:30,您可以忽略区域变量,只需获得2017-08-04T1 1:15:00.000。

function getLocalIsoDateTime(dtString) {
    if(dtString == "")
        return "";
    var offset = new Date().getTimezoneOffset();
    var localISOTime = (new Date(new Date(dtString) - offset * 60000 /*offset in milliseconds*/)).toISOString().slice(0,-1);
    //Next two lines can be removed if zone isn't needed.
    var absO = Math.abs(offset);
    var zone = (offset < 0 ? "+" : "-") + ("00" + Math.floor(absO / 60)).slice(-2) + ":" + ("00" + (absO % 60)).slice(-2);
    return localISOTime + zone;
}

其他回答

Date.prototype.toUTCArray= function(){
    var D= this;
    return [D.getUTCFullYear(), D.getUTCMonth(), D.getUTCDate(), D.getUTCHours(),
    D.getUTCMinutes(), D.getUTCSeconds()];
}

Date.prototype.toISO= function(){
    var tem, A= this.toUTCArray(), i= 0;
    A[1]+= 1;
    while(i++<7){
        tem= A[i];
        if(tem<10) A[i]= '0'+tem;
    }
    return A.splice(0, 3).join('-')+'T'+A.join(':');    
}

对于目标是将其作为“日期对象”而不是字符串获取的其他人,并且您只想显示不带TZ(可能是硬编码的)的日期/时间,您可以做的是:

const now = new Date();
const year = now.getUTCFullYear();
const month = now.getUTCMonth();
const day = now.getUTCDate();
const hour = now.getUTCHours();

const tomorrowUTC= new Date();
tomorrowUTC.setDate(day + 1); // +1 because my logic is to get "tomorrow"
tomorrowUTC.setYear(year);
tomorrowUTC.setMonth(month);
tomorrowUTC.Hours(hour);

// then use the tomorrowUTC for to display/format it
// tomorrowUTC is a "Date" and not a string.

然后,您可以执行以下操作:

我们将在${格式(明天UTC,'EEEE do MMMM hh:mmaa')}UTC删除您的帐户

(格式是一个日期fns函数,如果需要,可以使用其他lib);

这有点“黑客”,因为这仍然使用本地时区,但如果你只想显示日期而不是时区,那么这就可以了。

你想把日期转换成这样的字符串吗?

我会制作一个函数来实现这一点,尽管有点争议,但还是将其添加到Date原型中。如果你不习惯这样做,那么你可以把它作为一个独立的函数,把日期作为一个参数传递。

Date.prototype.getISOString = function() {
    var zone = '', temp = -this.getTimezoneOffset() / 60 * 100;
    if (temp >= 0) zone += "+";
    zone += (Math.abs(temp) < 100 ? "00" : (Math.abs(temp) < 1000 ? "0" : "")) + temp;

    // "2009-6-4T14:7:32+10:00"
    return this.getFullYear()   // 2009
         + "-"
         + (this.getMonth() + 1) // 6
         + "-"
         + this.getDate()       // 4
         + "T"
         + this.getHours()      // 14
         + ":"
         + this.getMinutes()    // 7
         + ":"
         + this.getSeconds()    // 32
         + zone.substr(0, 3)    // +10
         + ":"
         + String(temp).substr(-2) // 00
    ;
};

如果您在UTC时间需要它,只需使用getUTC*替换所有get*函数,例如:getUTCFullYear、getUTCMonth、getUTCHours。。。然后在末尾添加“+00:00”而不是用户的时区偏移。

处理日期时,我的建议是将日期解析为用户输入的各个字段。你可以把它当作一根完整的绳子,但你在玩火。

JavaScript可以以不同的格式处理两个相同的日期。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse

永远不要做类似的事情:

new Date('date as text');

一旦您将日期从用户输入解析到其各个字段中,就创建一个日期对象。创建日期对象后,通过添加时区偏移将其转换为UTC。由于DST,我无法强调使用日期对象的偏移量有多重要(这是另一个讨论来说明原因)。

var year = getFullYear('date as text');
var month = getMonth('date as text');
var dayOfMonth = getDate('date as text');

var date = new Date(year, month, dayOfMonth);

var offsetInMs = ((date.getTimezoneOffset() * 60)  // Seconds
                 * 1000);                          //  Milliseconds

var utcDate = new Date(date.getTime + offsetInMs);

现在,您可以将日期以UTC时间传递给服务器。我再次强烈建议不要使用任何日期字符串。要么将其传递给服务器,并将其细分为所需的最低粒度,例如年、月、日、分钟,要么将其作为一个值(如unix时期的毫秒)传递给服务器。

另一种转换为UTC并将其保留为日期对象的解决方案:(它的工作方式是从格式化字符串的末尾删除“GMT”部分,然后将其放回Date构造函数中)

var now=新日期();var now_utc=新日期(now.toUTCString().slice(0,-4));控制台日志(now_utc)

我需要这样做来与日期时间选择器库交互。但总的来说,这样处理约会是个坏主意。

用户通常希望使用本地时间的日期时间,因此您可以更新服务器端代码以正确解析带有偏移量的日期时间字符串,然后转换为UTC(最佳选项),或者在发送到服务器之前转换为UTC字符串(如Will Stern的回答)