javascript toISOString() 忽略时区偏移

Posted

技术标签:

【中文标题】javascript toISOString() 忽略时区偏移【英文标题】:javascript toISOString() ignores timezone offset [duplicate] 【发布时间】:2012-06-05 12:27:09 【问题描述】:

我现在正在尝试将 Twitter 日期时间转换为本地 iso 字符串(用于 prettyDate)2 天。我只是弄错了当地时间..

我正在使用以下函数:

function getLocalISOTime(twDate) 
    var d = new Date(twDate);
    var utcd = Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(),
        d.getMinutes(), d.getSeconds(), d.getMilliseconds());

    // obtain local UTC offset and convert to msec
    localOffset = d.getTimezoneOffset() * 60000;
    var newdate = new Date(utcd + localOffset);
    return newdate.toISOString().replace(".000", "");

在 newdate 中一切正常,但 toISOString() 再次将其扔回原来的时间...... 谁能帮我从 Twitterdate 中获取 iso 中的当地时间,格式为: 2012 年 5 月 31 日星期四 08:33:41 +0000

【问题讨论】:

你最后描述的格式不是ISO-8601E格式(另见Date.toISOString。你可以很容易地实现你想要的格式;它非常接近你用dateObj.toString()得到的格式. 试试看。 谢谢!结束了: var d = new Date(twDate); return new Date(d.toISOString().replace("Z", "-02:00")).toISOString().replace(".000", "");不是最漂亮的解决方案,但适用于我的时区。 @Bergi:自相矛盾的是,旧问题不能与新问题重复;) 这是一个没有任何手动时区设置的方法: var now = new Date(); now.setMinutes(now.getMinutes() - now.getTimezoneOffset()); var timeToSet = now.toISOString().slice(0,16); var elem = document.getElementById("eventdate"); elem.value = timeToSet; elem.min = timeToSet; 【参考方案1】:

moment.js 很棒,但有时您不想为简单的事情提取大量依赖项。

以下也可以:

    var tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds
    var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0, -1);
    
    console.log(localISOTime)  // => '2015-01-26T06:40:36.181'

slice(0, -1) 去掉了代表祖鲁时区的尾随 Z,可以用您自己的时区替换。

【讨论】:

简短而简单 - 太棒了!为了使其更具人类可读性,我将 .toISOString().slice(0,-5).replace("T", " ");在您的解决方案结束时。 时间以 UTC(协调世界时)表示,带有一个特殊的 UTC 指示符(“Z”)。 太好了,谢谢。在这里,作为一个带有可选日期参数的函数: function localISOTime(d) if (!d) d = new Date() var tzoffset = d.getTimezoneOffset() * 60000; //以毫秒为单位的偏移量 return (new Date(Date.now() - tzoffset)).toISOString().slice(0, -1); 为什么是“-”(现在的 tzoffset)? 您的解决方案不显示您的当地时间。它欺骗了日期,认为您的 UTC 日期是您的本地日期。你不应该改变你的日期你应该添加你的时区偏移【参考方案2】:

我不使用moment的解决方案是将其转换为时间戳,添加时区偏移量,然后转换回日期对象,然后运行toISOString()

var date = new Date(); // Or the date you'd like converted.
var isoDateTime = new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString();

【讨论】:

我喜欢这种方法。您的示例无法按原样工作,因为您尚未定义日期。如果你在前面加上 var date = new Date();以您的示例为例,它有效。 不使用库的绝佳解决方案,谢谢! 它有效!但我不明白你为什么乘以 60000 ? :s 漂亮而且非常简单。谢谢你。请注意:它确实在字符串末尾保留了“Z”,这在技术上是错误的,但很容易编辑。 @betoharres 就是将时区偏移量转换为毫秒,这就是getTime所在。【参考方案3】:

moment.js FTW!!!

只需将您的日期转换为一个时刻,然后随心所欲地对其进行操作:

var d = new Date(twDate);
var m = moment(d).format();
console.log(m);
// example output:
// 2016-01-08T00:00:00-06:00

http://momentjs.com/docs/

【讨论】:

这不是一个正确的答案...你能用 Moment.js 给出正确的答案吗?如果这是一个真正的答案,我可以每次回答“x86 FTW !!! intel.com/content/dam/www/public/us/en/documents/manuals/…”并说祝你好运...... When is “use jQuery” not a valid answer to a javascript question? 我在离线多年后登录只是为了注意这个答案允许格式化 Date 以便.NET API 接收带有 TimeZone 的日期并正确反序列化它。在 js 项目中拥有 moment.js 并没有那么糟糕,知道 ECMAScript 中的 Date API 缺少多少功能。 我在离线多年后登录只是为了注意答案中提供的解决方案允许在 ISO8601 中正确序列化本地时间。 moment.js 的存在是因为 ECMAScript 的 Date API 很烂。【参考方案4】:

下面这个日期函数不需要额外的脚本库就可以达到预期的效果。基本上它只是一个简单的以正确格式连接的日期组件,以及对 Date 对象原型的扩充。

 Date.prototype.dateToISO8601String  = function() 
    var padDigits = function padDigits(number, digits) 
        return Array(Math.max(digits - String(number).length + 1, 0)).join(0) + number;
    
    var offsetMinutes = this.getTimezoneOffset();
    var offsetHours = offsetMinutes / 60;
    var offset= "Z";    
    if (offsetHours < 0)
      offset = "-" + padDigits(offsetHours.replace("-","") + "00",4);
    else if (offsetHours > 0) 
      offset = "+" + padDigits(offsetHours  + "00", 4);

    return this.getFullYear() 
            + "-" + padDigits((this.getUTCMonth()+1),2) 
            + "-" + padDigits(this.getUTCDate(),2) 
            + "T" 
            + padDigits(this.getUTCHours(),2)
            + ":" + padDigits(this.getUTCMinutes(),2)
            + ":" + padDigits(this.getUTCSeconds(),2)
            + "." + padDigits(this.getUTCMilliseconds(),2)
            + offset;



Date.dateFromISO8601 = function(isoDateString) 
      var parts = isoDateString.match(/\d+/g);
      var isoTime = Date.UTC(parts[0], parts[1] - 1, parts[2], parts[3], parts[4], parts[5]);
      var isoDate = new Date(isoTime);
      return isoDate;       


function test() 
    var dIn = new Date();
    var isoDateString = dIn.dateToISO8601String();
    var dOut = Date.dateFromISO8601(isoDateString);
    var dInStr = dIn.toUTCString();
    var dOutStr = dOut.toUTCString();
    console.log("Dates are equal: " + (dInStr == dOutStr));

用法:

var d = new Date();
console.log(d.dateToISO8601String());

希望这对其他人有所帮助。

编辑

更正了 cmets 中提到的 UTC 问题,并将 Alex 归功于 dateFromISO8601 函数。

【讨论】:

这对我有帮助,我认为这是一个更好的答案。 虽然您获得了正确的本地时间,但您通过添加“Z”代替时区来错误地将时间与祖鲁时间相关联。如果您将由此创建的时间投入到任何符合 ISO 标准的应用程序中,您将不会得到正确的时间作为回报。您应该致电.getTimezoneOffset(),然后将分钟计算为小时格式,以使您的 ISO 日期符合要求。 那是错误的,我担心不起作用 现在您获得了 UTC 值,但将它们与本地时区偏移量结合起来? 按照代码当前的情况,这不会输出符合 ISO8601 的字符串,并且会为除 UTC 时区之外的所有字符串输出不正确的时间。符合 ISO8601 的偏移量采用 +HH:MM 而不是 +HH00 的形式。如果您要使用+/-NN:NN 后缀作为本地时区与Z 之间的偏移小时/分钟,则需要使用本地月份、日期、小时、分钟、秒和毫秒,而不是UTC 版本。此函数应称为Date.prototype.toLocalISOString,它更符合标准Date 函数。 dateFromISO8601 是不必要的,因为 new Date() 有效。【参考方案5】:

获取当前日期和时间会很有帮助。

var date=new Date();
  var today=new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().replace(/T/, ' ').replace(/\..+/, '');  

【讨论】:

【参考方案6】:

使用moment.js,可以使用toISOStringkeepOffset参数:

toISOString(keepOffset?: boolean): string;

moment().toISOString(true)

【讨论】:

【参考方案7】:

Moment js 解决方案是

var d = new Date(new Date().setHours(0,0,0,0));
m.add(m.utcOffset(), 'm')
m.toDate().toISOString()
// output "2019-07-18T00:00:00.000Z"

【讨论】:

以上是关于javascript toISOString() 忽略时区偏移的主要内容,如果未能解决你的问题,请参考以下文章

.toISOString() 函数的问题

date-fns 中的啥方法相当于 moment().toISOString()

TypeError:formats.dateTimeString.toISOString 不是函数

toISOString 在 iPhone 中无法与 Cordova Ionic 一起使用

Safari 为 Date toISOString() 返回了不正确的值

Javascript SetMonth 问题