从不带时区的日期获取ISO字符串

50

我的配置是里斯本时区。当我执行new Date()时,我会得到我的当前本地日期/时间,即Fri Apr 28 2017 01:10:55 GMT+0100(GMT夏令时)

当我使用toISOString()获取ISO字符串时,它将应用时区并返回:

2017-04-28T00:10:55.964Z

问题在于几分钟前日期时间是这样的(昨天):

2017-04-27T23:45:05.654Z

我尝试了moment.js(对此还不熟悉),然后我做了这样的事情

document.write(moment('2017-04-28').format())

但是我得到了这个2017-04-28T00: 00: 00 +01: 00,而不是2017-04-28T00: 00: 00.000Z

我想将此值作为restful方法的参数传递,以便自动将其解析为DateTime类型,但如果我传递moment.js格式的输出,则会将其解析为2017-04-27 23: 00: 00.00

如果我使用new Date()或者new Date('2017-04-27')(仅日期部分),我只希望获得以下ISO格式,没有时区:

2017-04-28T00:00:00.000Z

有没有类似于toISOString()的javascript方法,或者使用moment库来获取这种格式?

无论时区或时间点是什么,我只想模拟给定日期的午夜时间。


2
一个没有时区的日期/时间值通常是没有用的,除非假定时区是特定的(如UTC)。这是你想要的吗? - Pointy
17个回答

31

你的问题不是很清楚。如果你想要UTC时间日期中小时始终为0,那么将UTC小时设置为0并使用toISOString即可,例如:

var d = new Date();
d.setUTCHours(0,0,0,0);
console.log(d.toISOString());

当然,这将显示UTC日期,可能与生成Date的系统上的日期不同。

另外,

new Date('2017-04-27').toISOString();

应该返回2017-04-27T00:00:00Z(即应根据ECMA-262解析为UTC,这与ISO 8601相反,后者将其视为本地时间),但是在所有正在使用的实现中都不可靠。

如果您只想以ISO 8601格式获取当前日期,可以执行以下操作:

if (!Date.prototype.toISODate) {
  Date.prototype.toISODate = function() {
    return this.getFullYear() + '-' +
           ('0'+ (this.getMonth()+1)).slice(-2) + '-' +
           ('0'+ this.getDate()).slice(-2);
  }
}

console.log(new Date().toISODate());

然而,由于内置的toISOString使用的是UTC时间,这可能会令人困惑。如果需要UTC日期,则:

if (!Date.prototype.toUTCDate) {
  Date.prototype.toUTCDate = function() {
    return this.getUTCFullYear() + '-' +
           ('0'+ (this.getUTCMonth()+1)).slice(-2) + '-' +
           ('0'+ this.getUTCDate()).slice(-2);
  }
}

console.log(new Date().toUTCDate());


1
这对我很有帮助。我正在寻找当前客户端UTC日期(不带时区或时间戳)。 - nmante
1
@PatrickSzalapski,你的“更简便”的版本并没有做同样的事情,因为你的子字符串将从UTC而不是本地日期中获取,这在一天中的某些小时内会有所不同。 - Andy
啊,当然。谢谢你指出来。我已经删除了我的评论以避免混淆。 - Patrick Szalapski

18

old_date = Fri Jan 08 2021 16:01:30 GMT+0900

const new_date = old_date.toISOString().substring(0, 10);

新日期 = "2021-01-08"


虽然这段代码可能解决了问题,但是包括解释它如何以及为什么解决了问题将有助于提高您的帖子质量,并可能导致更多的赞。请记住,您正在回答未来读者的问题,而不仅仅是现在提问的人。请[编辑]您的答案以添加解释并指出适用的限制和假设。 - Yunnosch
1
请讨论为什么您认为最受欢迎的旧答案中提出的解决方案不可靠,特别是为什么您提出了完全相同的解决方案。也就是说,您的贡献并不新颖,您需要指出它与当前被认为有缺陷的概念相比的优势。还有另一个旧答案,虽然没有得到赞同,但提出了与您相同的解决方案,并至少提供了一些信息链接。在这里,抄袭其他答案或因未阅读现有答案而重新发布它们是不受欢迎的,因为这不会为问答集合提供额外的价值。 - Yunnosch
只是想在这里提供一个简单的解决方案。我没有很多时间,绝对不会从别人那里复制粘贴。实际上,在上面并没有像我的答案一样的答案,尽管在再次阅读时,有人在评论中放了类似的东西。如果你有更多的时间来添加解释,可以自由地编辑它,如果没有,我会把它留在这里供那些可能会发现它有用的人使用(并且没有太多时间阅读为什么我的解决方案比其他任何解决方案好或差的解释)。 - Damien Minter
4
这个一行代码对于任何JavaScript开发者来说都很清晰,简单而且有效,它只是移除日期字符串中不需要的时间字符。我想知道为什么之前没有人想到这种解决方案。我找不到那个旧答案,其中据说已经回答了这个解决方案。 - AxeEffect
然而我同意它需要进一步的样式修饰。第一行和最后一行应该是代码块的一部分。第一行:const old_date = new Date("Fri Jan 08 2021 16:01:30 GMT+0900");。最后一行:console.log(new_date); // "2021-01-08"。即使解决方案不言自明,一个一行的介绍也能更好地呈现解决方案。 - AxeEffect

17
你可以通过使用 moment.format() 将需要的所有内容格式化到位并简单地将额外的 Z 添加到字符串中来实现此目的。你必须这样做,因为 moment JS 中的 Z 保留用于输出。
var date = moment('2014-08-28').format("YYYY-MM-DDT00:00:00.000") + "Z";

示例程序https://jsfiddle.net/2avxxz6q/


谢谢你的回答。但是它不是输出为2017-04-27T23:00:00.000Z,我需要的是2017-04-28T00:00:00.000Z。对于我来说,今天已经是4月28日而不是4月27日。 - Maximus Decimus
我更新了我的答案,如果你不担心时间组件,就包括了一个替代方案。 - li x
又进行了更改并在此处测试输出 https://jsfiddle.net/2avxxz6q/ @MaximusDecimus - li x

9

你可以尝试这个,对我有效!你将获得没有时区影响的ISO格式

Fri Jan 01 2021 23:10:00 GMT+0100 => 2021-01-01T23:10:00.000Z

function isoDateWithoutTimeZone(date) {
  if (date == null) return date;
  var timestamp = date.getTime() - date.getTimezoneOffset() * 60000;
  var correctDate = new Date(timestamp);
  // correctDate.setUTCHours(0, 0, 0, 0); // uncomment this if you want to remove the time
  return correctDate.toISOString();
}


        var now= new Date("01-01-2021 23:10:00");
        console.log(now.toString());
        var returnedDate = isoDateWithoutTimeZone(now);
        console.log(returnedDate);


2
我写了一个简单的函数,可以扩展 moment js 对象:
moment.fn.toISOStringWithoutTimezone = function () {
  return this.format("YYYY-MM-DD[T]HH:mm:ss");
};

它可以像这样使用:
moment().toISOStringWithoutTimezone();

2
您不需要使用 moment.js 库,您可以直接解析和连接日期组件。例如:
type Components = {
  day: number,
  month: number,
  year: number
}

export default class DateFormatter {
  // 2018-11-11T00:00:00
  static ISOStringWithoutTimeZone = (date: Date): string => {
    const components = DateFormatter.format(DateFormatter.components(date))
    return `${components.year}-${components.month}-${components.day}T00:00:00`
  }

  static format = (components: Components) => {
    return {
      day: `${components.day}`.padStart(2, '0'),
      month: `${components.month}`.padStart(2, '0'),
      year: components.year
    }
  }

  static components = (date: Date): Components => {
    return {
      day: date.getDate(),
      month: date.getMonth() + 1,
      year: date.getFullYear()
    }
  }
}

2
虽然您可能不需要moment,但是这段代码看起来确实像是在重新发明轮子,对于一个3.2kb的gzip,我仍然会选择使用moment。 - li x

2

还有另一种棘手的方法,你可以从this的答案中了解。在瑞典日期格式中,你可以轻松地将日期转换为下面的Iso格式:

new Intl.DateTimeFormat('sv-SE').format(new Date());//'2022-07-08'


1

我的问题: 我需要一直将日期和时间发送到服务器API中的ISO格式。要解决这个问题,我可以简单地使用 new Date().toISOString(),但是我的客户端应用程序可能在不同的时区下运行,因此始终会有时区差异。

解决方案: 为了解决这个问题,我参考了上面提供的解决方案,即手动创建ISO格式字符串,而不考虑给定的时区。

function getISOString(date)
{
let d = new Date(date),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = ''+ d.getFullYear(),
hours = ''+d.getHours(),
minutes = ''+d.getMinutes(),
seconds = ''+d.getSeconds();
month = month.length < 2? '0' + month : month;
day   = day.length < 2? '0' + day : day;
hours = hours.length < 2?'0'+hours:hours;
minutes = minutes.length< 2? '0'+minutes:minutes;
seconds = seconds.length< 2? '0'+seconds:seconds;
return ( [year, month, day].join('-')+'T'+[hours,minutes,seconds].join(':')+'.000');
}
console.log(getISOString(new Date()));

1

你救了我,保持偏移量的解决方案太棒了! - Jhony Spark

0

虽然此链接可以回答问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面发生更改,则仅有链接的答案可能会变得无效。-【来自审查】 - Chris C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接