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

2009-1-1 to 2009-1-3

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

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

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

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


当前回答

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

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

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

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

其他回答

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(':');    
}

我刚刚发现Steven Levithan的date.format.js的1.2.3版本正是我想要的。它允许您为JavaScript日期提供格式字符串,并将从本地时间转换为UTC。下面是我现在使用的代码:

// JavaScript dates don't like hyphens!    
var rectifiedDateText = dateText.replace(/-/g, "/");
var d = new Date(rectifiedDateText);

// Using a predefined mask from date.format.js.
var convertedDate = dateFormat(d, 'isoUtcDateTime'); 

这是我的方法:

var now = new Date();
var utc = new Date(now.getTime() + now.getTimezoneOffset() * 60000);

生成的utc对象实际上不是utc日期,而是转换为与utc时间匹配的本地日期(请参见注释)。然而,在实践中,它确实起到了作用。


更新:当调用UTC.toString()、UTC.toLocaleString()等时,这个答案是获取UTC日期的一种快速而肮脏的方法。不过,有更好的解决方案,尤其是现在使用现代浏览器的情况下,我应该改进一下答案。基本上,.toISOString()(IE 9+)是您想要使用的。

我的解决方案使日期保持不变,无论客户端上设置了什么时区。也许有人会发现它很有用。

我的用例:

我正在创建一个todo应用程序,您可以在其中设置任务日期。无论您在哪个时区,此日期都应保持不变。

实例你想在6月25日早上8点给你的朋友打电话。

您在中国时,在5天前(6月20日)创建此任务。

然后,在同一天,你飞往纽约几天。

然后在6月25日,当你还在纽约时,你在早上7:30醒来(这意味着你应该在30分钟内收到任务通知(即使在中国,你创建任务时已经是下午1:30)

因此,任务是忽略时区。这意味着“我想在早上8点在任何时区做这件事”。

我所做的是让我们说“我假设你总是在伦敦时区-UTC”。

这意味着-当用户在她/他的时区中选择某个日期时-我将此日期转换为UTC中的相同日期。也就是说,你在中国选择上午8点,但我将其转换为UTC的上午8点。

然后-下次你打开应用程序时-我读取以UTC保存的日期,并将其转换为当前时区中的相同日期-例如,我将UTC中的上午8点转换为纽约时区中的早上8点。

这个解决方案意味着,日期可能意味着其他东西,这取决于你在设置日期时的位置和阅读日期的位置,但它保持不变,“感觉”你总是在同一时区。

让我们编写一些代码:

首先,我们有两个主要函数用于从UTC转换为UTC,忽略时区:

export function convertLocalDateToUTCIgnoringTimezone(date: Date) {
  const timestamp = Date.UTC(
    date.getFullYear(),
    date.getMonth(),
    date.getDate(),
    date.getHours(),
    date.getMinutes(),
    date.getSeconds(),
    date.getMilliseconds(),
  );

  return new Date(timestamp);
}

export function convertUTCToLocalDateIgnoringTimezone(utcDate: Date) {
  return new Date(
    utcDate.getUTCFullYear(),
    utcDate.getUTCMonth(),
    utcDate.getUTCDate(),
    utcDate.getUTCHours(),
    utcDate.getUTCMinutes(),
    utcDate.getUTCSeconds(),
    utcDate.getUTCMilliseconds(),
  );
}

然后,我保存/读取此日期,如:

function saveTaskDate(localDate: Date) {
  // I convert your local calendar date so it looks like you've picked it being in UTC somewhere around London
  const utcDate = convertLocalDateToUTCIgnoringTimezone(localDate);
  api.saveTaskDate(utcDate);
}

function readTaskDate(taskUtcDate: Date) {
  // I convert this UTC date to 'look in your local timezone' as if you were now in UTC somewhere around london
  const localDateWithSameDayAsUTC = convertUTCToLocalDateIgnoringTimezone(taskUtcDate);

  // this date will have the same calendar day as the one you've picked previously
  // no matter where you were saving it and where you are now
}

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

我会制作一个函数来实现这一点,尽管有点争议,但还是将其添加到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”而不是用户的时区偏移。