解析日期而不带时区javascript


147

我想在JavaScript中解析没有时区的日期。我努力了:

new Date(Date.parse("2005-07-08T00:00:00+0000"));

返回时间:2005年7月8日星期五,格林尼治标准时间 +0200 (欧洲中部夏令时)

new Date(Date.parse("2005-07-08 00:00:00 GMT+0000"));

返回相同的结果

new Date(Date.parse("2005-07-08 00:00:00 GMT-0000"));

返回相同的结果

我想解析时间:

  1. 没有时区。

  2. 无需调用构造函数Date.UTC或新的Date(年,月,日)。

  3. 只需将字符串简单地传递到Date构造函数即可(无需原型方法)。

  4. 我必须提供Date对象,而不是String


3
您可以省略Date.parsebtw并将字符串直接传递给Date构造函数。
Bergi

1
我不确定您为什么需要这样做,但我很确定Date始终具有用户的本地时区。如果您希望JavaScript与其他时区一起使用,而不必为Date使用包装对象,那么这可能对您有用
HMR

1
不幸的是,我不得不复制Date对象以获得正确的对象来比较MongoDB中的日期:new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate())
Athlan

如果要分析没有时间的日期,则需要指定要采用的时区,因为“ 2005-07-08”在不同时区中的含义不同。截至2020年5月,由于实施方面的差异,MDN文档建议不要使用任何内置日期解析功能。但是,使用Date.parse(“ 2005-07-08”)可能会返回UTC时间00:00。另一方面,date-fns解析时,解析相同的日期字符串时将返回本地时间00:00
Andy

Answers:


106

日期已正确解析,只是toString会将其转换为您的本地时区:

let s = "2005-07-08T11:22:33+0000";
let d = new Date(Date.parse(s));

// this logs for me 
// "Fri Jul 08 2005 13:22:33 GMT+0200 (Central European Summer Time)" 
// and something else for you

console.log(d.toString()) 

// this logs
// Fri, 08 Jul 2005 11:22:33 GMT
// for everyone

console.log(d.toUTCString())

Javascript Date对象是时间戳-自时代起它们仅包含毫秒数。Date对象中没有时区信息。此时间戳表示哪个日历日期(天,分钟,秒)取决于解释(to...String方法之一)。

上面的示例显示日期已正确解析-也就是说,它实际上包含与GMT中的“ 2005-07-08T11:22:33”相对应的毫秒数。


4
不幸的是,我必须产生Date对象,而不是String。
阿斯兰

@Athlan:添加了一些说明。
乔治,

1
我已经检查过了。我已将解析后的日期传递给MongoDB查询new Date(Date.parse("2005-07-08T11:22:33+0000")),并通过构造函数复制日期:new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate())。两种解决方案,结果不同,第二正确!您的回复很有用,就像在hunlock.com/blogs/Javascript_Dates-The_Complete_Reference中提到的那样。向上。
Athlan

对我来说完美地工作-.toUTCString()是使我从原始给定字符串返回正确时间的工单。即new Date(“ 2016-08-22T19:45:00.0000000”)。toUTCString()
Michael Giovanni Pumo

38
JavaScript日期和时间中所有邪恶的根源都包含在您的第一句话中……只是toString会将其转换为您当地的时区...在这里,单一责任在哪里?toString方法应该只对结果进行字符串化,而不要对其进行转换。如果要转换日期,则应该使用其他方法。
主播

109

我有同样的问题。我以字符串形式获取日期,例如:'2016-08-25T00:00:00',但是我需要具有正确时间的Date对象。要将String转换为对象,我使用getTimezoneOffset:

var date = new Date('2016-08-25T00:00:00')
var userTimezoneOffset = date.getTimezoneOffset() * 60000;
new Date(date.getTime() - userTimezoneOffset);

getTimezoneOffset()将返回以太坊的负值或正值。必须减去它才能在世界上的每个位置工作。


6
我有同样的问题,发现这很有帮助。但是,我发现由于夏令时,该功能无法处理时区偏移。示例:我在太平洋标准时间(PST),所以我当前(格林威治标准时间)与GMT的偏移量为-8:00,但5月为-7:00。我的解决方案是进行计算var userTimezoneOffset = date.getTimezoneOffset()*60000;
mmh02,2017年

3
除非我是一个完全的白痴,否则这实际上会返回错误的时间。getTimezoneOffset()返回与您认为相反的分钟数-我的时区现在是UTC-4,但getTimezoneOffset()返回正数240。因此userTimezoneOffset应从中减去date.getTime(),而不要加进去。
vaindil '18

1
我同意@vaindil,您应该减去。wakwa的解决方案仅在您对格林威治的看法正确时才有效。Wakwas应该纠正它。
珍妮·哈祖

1
啊! 讲得太早了。它不适用于大多数时区。我可以确认将GEST时间与AEST&CEST时间相抵消时返回错误的日期。
saran3h

1
@vaindil现在的结果与new Date('2016-08-25T00:00:00Z')我认为关键是要进行操纵new Date('2016-08-25T00:00:00Z')以便本地时间显示为0:00,但此代码丢失Z
barbsan

14

我遇到了同样的问题,然后想起了我正在从事的旧项目以及他们如何处理此问题的一些小问题。当时我不了解,也没真正在乎,直到我自己遇到问题

var date = '2014-01-02T00:00:00.000Z'
date = date.substring(0,10).split('-')
date = date[1] + '-' + date[2] + '-' + date[0]

new Date(date) #Thu Jan 02 2014 00:00:00 GMT-0600

无论出于什么原因,将日期传递为'01 -02-2014'都会将时区设置为零,并忽略用户的时区。这可能是Date类中的偶然现象,但它存在于一段时间之前,而今天却存在。它似乎可以跨浏览器工作。自己尝试一下。

该代码是在一个时区非常重要的全球项目中实现的,但是查看日期的人并不在乎引入它的确切时间。


我认为这是有意的,因为“ Z”表示JS然后转换的UTC,但是由于没有时区,它无法转换,因此它基本上假定了用户的时区。希望得到一些确认或更好的解释。
dlsso 2016年

7
不稳定的行为是由于破折号。Chrome浏览器,Firefox和IE11的所有解释2014/5/31,并2014/05/31为周六2014年5月31日00:00:00 GMT-0600(山区夏令时间)`(MDT是我目前的时区)。带有破折号...所有浏览器都将其解释2014-05-31为2014年5月30日星期五,格林尼治标准时间0600(山地夏令时)。奇怪的是,使用2014-5-31,Chrome将返回星期六,而Firefox将返回星期五,而IE11说该日期无效。似乎date.replace('-','/')可以解决问题。
atheaos

6

Date对象本身将包含时区无论如何,返回的结果是一个默认的方式将其转换为字符串的效果。即您不能创建没有时区的日期对象。但是您可以做的是Date通过创建自己的对象来模仿对象的行为。但是,最好将其移交给moment.js之类的


2
不幸的是,我必须产生Date对象,而不是String。
Athlan

3

简单的解决方案

const handler1 = {
  construct(target, args) {
    let newDate = new target(...args);
    var tzDifference = newDate.getTimezoneOffset();
    return new target(newDate.getTime() + tzDifference * 60 * 1000);
  }
};

Date = new Proxy(Date, handler1);

3

javascript中的日期只是使其内部保持简单。因此日期时间数据存储在UTC Unix纪元(毫秒或ms)中。

如果您希望地球上的任何时区都没有固定的“固定”时间,则可以调整UTC时间以匹配您当前的本地时区并保存。取回时,无论您身在本地时区如何,它都会根据保存它的人显示调整后的UTC时间,并加上本地时区偏移量以获得“固定”时间。

保存日期(以毫秒为单位)

toUTC(datetime) {
  const myDate = (typeof datetime === 'number')
    ? new Date(datetime)
    : datetime;

  if (!myDate || (typeof myDate.getTime !== 'function')) {
    return 0;
  }

  const getUTC = myDate.getTime();
  const offset = myDate.getTimezoneOffset() * 60000; // It's in minutes so convert to ms
  return getUTC - offset; // UTC - OFFSET
}

检索/显示日期(以毫秒为单位)

fromUTC(datetime) {
  const myDate = (typeof datetime === 'number')
    ? new Date(datetime)
    : datetime;

  if (!myDate || (typeof myDate.getTime !== 'function')) {
    return 0;
  }

  const getUTC = myDate.getTime();
  const offset = myDate.getTimezoneOffset() * 60000; // It's in minutes so convert to ms
  return getUTC + offset; // UTC + OFFSET
}

那么你就可以:

const saveTime = new Date(toUTC(Date.parse("2005-07-08T00:00:00+0000")));
// SEND TO DB....

// FROM DB...
const showTime = new Date(fromUTC(saveTime));

2

您可以使用此代码

var stringDate = "2005-07-08T00:00:00+0000";
var dTimezone = new Date();
var offset = dTimezone.getTimezoneOffset() / 60;
var date = new Date(Date.parse(stringDate));
date.setHours(date.getHours() + offset);

1
我不认为这会考虑到夏令时
Daniel Thompson

2

由于在显示日期时(例如在当地时间显示),这确实是一个格式问题,因此,我喜欢使用new(ish)Intl.DateTimeFormat对象执行格式化,因为它更加明确并提供了更多输出选项:

const dateOptions = { timeZone: 'UTC', month: 'long', day: 'numeric', year: 'numeric' };

const dateFormatter = new Intl.DateTimeFormat('en-US', dateOptions);
const dateAsFormattedString = dateFormatter.format(new Date('2019-06-01T00:00:00.000+00:00'));

console.log(dateAsFormattedString) // "June 1, 2019"

如图所示,将timeZone设置为'UTC'不会执行本地转换。另外,它还允许您创建更多优化的输出。您可以从Mozilla-Intl.DateTimeFormat中了解有关Intl.DateTimeFormat对象的更多信息。

编辑:

无需创建新Intl.DateTimeFormat对象即可实现相同的功能。只需将语言环境和日期选项直接传递给toLocaleDateString()函数即可。

const dateOptions = { timeZone: 'UTC', month: 'long', day: 'numeric', year: 'numeric' };
const myDate = new Date('2019-06-01T00:00:00.000+00:00');
today.toLocaleDateString('en-US', dateOptions); // "June 1, 2019"

1

只是一般性的注释。一种保持灵活性的方法。

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date

我们可以使用getMinutes(),但在前9分钟内它仅返回一个数字。

let epoch = new Date() // Or any unix timestamp

let za = new Date(epoch),
    zaR = za.getUTCFullYear(),
    zaMth = za.getUTCMonth(),
    zaDs = za.getUTCDate(),
    zaTm = za.toTimeString().substr(0,5);

console.log(zaR +"-" + zaMth + "-" + zaDs, zaTm)

Date.prototype.getDate()
    Returns the day of the month (1-31) for the specified date according to local time.
Date.prototype.getDay()
    Returns the day of the week (0-6) for the specified date according to local time.
Date.prototype.getFullYear()
    Returns the year (4 digits for 4-digit years) of the specified date according to local time.
Date.prototype.getHours()
    Returns the hour (0-23) in the specified date according to local time.
Date.prototype.getMilliseconds()
    Returns the milliseconds (0-999) in the specified date according to local time.
Date.prototype.getMinutes()
    Returns the minutes (0-59) in the specified date according to local time.
Date.prototype.getMonth()
    Returns the month (0-11) in the specified date according to local time.
Date.prototype.getSeconds()
    Returns the seconds (0-59) in the specified date according to local time.
Date.prototype.getTime()
    Returns the numeric value of the specified date as the number of milliseconds since January 1, 1970, 00:00:00 UTC (negative for prior times).
Date.prototype.getTimezoneOffset()
    Returns the time-zone offset in minutes for the current locale.
Date.prototype.getUTCDate()
    Returns the day (date) of the month (1-31) in the specified date according to universal time.
Date.prototype.getUTCDay()
    Returns the day of the week (0-6) in the specified date according to universal time.
Date.prototype.getUTCFullYear()
    Returns the year (4 digits for 4-digit years) in the specified date according to universal time.
Date.prototype.getUTCHours()
    Returns the hours (0-23) in the specified date according to universal time.
Date.prototype.getUTCMilliseconds()
    Returns the milliseconds (0-999) in the specified date according to universal time.
Date.prototype.getUTCMinutes()
    Returns the minutes (0-59) in the specified date according to universal time.
Date.prototype.getUTCMonth()
    Returns the month (0-11) in the specified date according to universal time.
Date.prototype.getUTCSeconds()
    Returns the seconds (0-59) in the specified date according to universal time.
Date.prototype.getYear()
    Returns the year (usually 2-3 digits) in the specified date according to local time. Use getFullYear() instead. 

-1

(new Date().toString()).replace(/ \w+-\d+ \(.*\)$/,"")

这将有输出:Tue Jul 10 2018 19:07:11

(new Date("2005-07-08T11:22:33+0000").toString()).replace(/ \w+-\d+ \(.*\)$/,"")

这将具有输出:Fri Jul 08 2005 04:22:33

注意:返回的时间取决于您当地的时区


-1

这是我针对此问题想出的解决方案,对我有用。


使用的库:带有普通javascript Date类的momentjs。

步骤1.将String date转换为moment对象(PS:只要toDate()不调用method,moment就会保留原始的日期和时间):

const dateMoment = moment("2005-07-08T11:22:33+0000");

步骤2. 从先前创建的矩对象中提取hoursminutes值:

  const hours = dateMoment.hours();
  const mins = dateMoment.minutes();

步骤3.将时间转换为日期(PS:这将根据您的浏览器/机器的时区来更改原始日期,但请不要担心,请阅读步骤4。):

  const dateObj = dateMoment.toDate();

步骤4.手动设置步骤2中提取的小时和分钟。

  dateObj.setHours(hours);
  dateObj.setMinutes(mins);

步骤5. dateObj现在将显示原始日期,没有任何时区差异。由于我们手动设置原始的小时和分钟,因此即使是夏令时更改也不会对日期对象产生任何影响。

希望这可以帮助。


-7

默认情况下,日期解析存在一些固有的问题,这些问题无法很好地解决。

-人类可读的日期在其中具有隐式时区
-网络上有许多广泛使用的日期格式含糊不清

要解决这些问题既简单又干净,需要使用以下功能:

>parse(whateverDateTimeString,expectedDatePattern,timezone)
"unix time in milliseconds"

我已经搜索过了,但是什么也没找到!

所以我创建了:https : //github.com/zsoltszabo/timestamp-grabber

请享用!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.