Разобрать дату без часового пояса


147

Я хочу разобрать дату без часового пояса в JavaScript. Я пытался:

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

Возвращает пт 08 июля 2005 02:00:00 GMT + 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 или новой даты (год, месяц, день).

  3. Простая передача строки в конструктор Date (без подходов к прототипу).

  4. Я должен продукт Date, а не объект String.


3
Вы можете просто пропустить Date.parsebtw и напрямую передать строку в Dateконструктор.
Берги

1
Я не уверен, зачем вам это нужно, но я уверен, что у Date всегда есть местный часовой пояс пользователя. Если вы хотите, чтобы ваш JavaScript работал с другими часовыми поясами, чем вы должны будете использовать объект-обертку для даты, возможно, это подойдет вам: github.com/mde/timezone-js
HMR

1
К сожалению, мне пришлось скопировать Dateобъект, чтобы получить правильный объект для сравнения дат в MongoDB:new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate())
Athlan

Если вы хотите проанализировать дату без времени, вам нужно указать, какой часовой пояс вы хотите использовать, поскольку «2005-07-08» означает разные вещи в разных часовых поясах. Начиная с мая 2020 года документация по MDN не допускает каких-либо встроенных функций анализа дат из-за различий в реализации. Однако использование Date.parse ("2005-07-08"), вероятно, вернет время 00:00 UTC. Анализ par date-fns, с другой стороны, вернет 00:00 по местному времени при разборе той же строки даты
Энди

Ответы:


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())

Объект Date в формате Javascript - это временные метки - они просто содержат количество миллисекунд с начала эпохи. В объекте Date нет информации о часовом поясе. Какую календарную дату (день, минуты, секунды) представляет эта временная метка, зависит от интерпретации (один из to...Stringметодов).

Приведенный выше пример показывает, что дата анализируется правильно, то есть фактически содержит количество миллисекунд, соответствующих «2005-07-08T11: 22: 33» в GMT.


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 . Up.
Атлан

У меня отлично сработало - .toUTCString () был тикетом, который дал мне правильное время возврата от исходной заданной строки. то есть новая дата ("2016-08-22T19: 45: 00.0000000"). toUTCString ()
Майкл Джованни Пумо

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, но в мае это будет -7: 00. Моим решением было рассчитатьvar userTimezoneOffset = date.getTimezoneOffset()*60000;
ммх02

3
Если я не полный идиот, это на самом деле возвращает неправильное время. getTimezoneOffset()возвращает количество минут в обратном направлении, которое вы думаете - мой часовой пояс сейчас UTC-4, но getTimezoneOffset()возвращает положительное значение 240. Поэтому его userTimezoneOffsetследует вычесть из date.getTime(), а не добавить к нему.
vaindil

1
Я согласен с @vaindil вы должны вычесть. Решение wakwa работает только тогда, когда вы находитесь на правильной стороне Гринвича. Ваквас должен исправить это.
Янне Харью

1
Ах! говорил слишком рано. Это не работает для большинства часовых поясов. Я могу подтвердить, что он возвращает неправильную дату при смещении времени AEST и CEST по времени GMT.
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" обозначает UTC, которое затем преобразует JS, но без часового пояса не может преобразовать его, поэтому, по сути, предполагает часовой пояс пользователя. Хотел бы получить подтверждение или лучшее объяснение, хотя.
dlsso

7
Шаткое поведение связано с тире. Chrome, Firefox, и IE11 все интерпретировать 2014/5/31и , 2014/05/31как СБ 31 мая 2014 00:00:00 GMT-0600 (Mountain летнее время) `(MDT будучи моей текущей временной зоны). С тире ... все браузеры интерпретируются 2014-05-31как пт 30 мая 2014 18:00:00 GMT-0600 (горное летнее время). Как ни странно, с 2014-5-31Chrome возвращается суббота, Firefox возвращается в пятницу, а IE11 говорит, что дата недействительна. Похоже, что date.replace('-','/')может сделать свое дело.
atheaos

6

В Dateлюбом случае сам объект будет содержать часовой пояс, а возвращаемый результат является результатом преобразования его в строку по умолчанию. Т.е. вы не можете создать объект даты без часового пояса. Но вы можете имитировать поведение Dateобъекта, создавая свой собственный. Это, однако, лучше передавать в библиотеки, такие как moment.js .


2
К сожалению, я должен создать объект Date, а не String.
Атлан

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 (миллисекунды или мс).

Если вы хотите иметь «фиксированное» время, которое не меняется ни в каком часовом поясе на Земле, вы можете отрегулировать время в 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
Я не верю, что это учитывает переход на летнее время
Дэниел Томпсон

2

Так как это действительно проблема форматирования при отображении даты (например, отображение по местному времени), мне нравится использовать новый (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"

Как показано, при установке часового пояса в «UTC» он не будет выполнять локальные преобразования. В качестве бонуса, он также позволяет создавать более полированные результаты. Вы можете прочитать больше об объекте Intl.DateTimeFormat из Mozilla - 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/en-US/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+ \(.*\)$/,"")

Это будет иметь выход: вт 10 июля 2018 19:07:11

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

Это будет иметь выход: пт 08 июля 2005 04:22:33

Примечание: время возврата будет зависеть от вашего местного часового пояса


-1

Это решение, которое я придумал для этой проблемы, которое работает для меня.


используемая библиотека: моменты с простым javascript классом Date.

Шаг 1. Преобразовать строковую дату в момент объекта (PS: момент сохраняет исходную дату и время, пока toDate()метод не вызывается):

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

Шаг 2. Извлечение hoursи minutesзначения из ранее созданного момента объекта:

  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

Наслаждайтесь!

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.