Является ли объект даты Javascript всегда одним выходным?

238

В моем приложении Java Script дата хранится в следующем формате:

2011-09-24

Теперь, когда я пытаюсь использовать указанное выше значение для создания нового объекта Date (чтобы я мог получить дату в другом формате), дата всегда возвращается на один выходной. Увидеть ниже:

var doo = new Date("2011-09-24");
console.log(doo);

журналы:

Fri Sep 23 2011 20:00:00 GMT-0400 (Eastern Daylight Time)
Levi
источник
11
Класс Date в Javascript не представляет дату, он представляет временную метку (то же самое в Java). Чтобы сделать его датой, он использует часовой пояс, и это является причиной вашей проблемы. Он анализирует его часовой пояс GMT / UTC (24 сентября 2011, 00 : 00 по Гринвичу) , а затем выводит его с другим часовым поясом 4 часов (23 Сен 2011, 20 : 00 GMT-0400).
Кодо
2
Я получаю "недопустимую дату". Замените символы «-» на символы «/» и повторите попытку. Или разделите дату на биты и установите компоненты по отдельности (если вы это сделаете, вычтите 1 из номера месяца).
RobG
@ Кодо - да, хороший ответ. ECMA-262 15.9.1.15 применяется. ОП должен использовать «2011-09-24T20: 00: 00-04: 00» или аналогичный.
RobG
1
Я обнаружил, что формат «24 сентября 2011» вернет правильную дату. Смотрите здесь для объяснения: stackoverflow.com/questions/2587345/javascript-date-parse
christurnerio

Ответы:

98

Обратите внимание, что восточное летнее время -4 hoursи что часы в дату, когда вы возвращаетесь, являются 20.

20h + 4h = 24h

которая полночь 2011-09-24. Дата была проанализирована в UTC (GMT), потому что вы указали строку только для даты без индикатора часового пояса. Если бы вместо new Date("2011-09-24T00:00:00")этого вы указали строку даты / времени без индикатора ( ), он был бы проанализирован в вашем местном часовом поясе. (Исторически там были несоответствия, не в последнюю очередь потому, что спецификация менялась более одного раза, но современные браузеры должны быть в порядке; или вы всегда можете включить индикатор часового пояса.)

Вы получаете правильную дату, вы просто не указали правильный часовой пояс.

Если вам нужен доступ к значениям даты, вы можете использовать getUTCDate()или любую другую getUTC*()функцию :

var d,
    days;
d = new Date('2011-09-24');
days = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'];
console.log(days[d.getUTCDay()]);
zzzzBov
источник
24
Как вы «указываете правильный часовой пояс»? Конструктор даты всегда интерпретирует строку даты как UTC, но затем корректирует часовой пояс. Я даже могу сделать `новую дату ('2012-01-02 EDT') и все равно перенести ее обратно на предыдущий день из-за применения смещения для перехода на летнее время, что не имеет смысла, потому что, если я скажу вам, что это дата согласно текущий часовой пояс EDT, затем не применяйте к нему дополнительное смещение. Я сказал, что часовой пояс был EDT, но он все еще применяет дополнительное смещение, перемещая его на один день назад.
AaronLS
1
@AaronLS, EDTэто летнее время (также известное как летнее время) , ESTэто часовой пояс, который применяется в январе.
zzzzBov
1
Я хотел бы создать его как UTC из строки, поэтому я спросил: «Как вы» указываете правильный часовой пояс? » относительно того, где вы указали «вы просто никогда не указали правильный часовой пояс». Если я это сделаю, new Date('2012-01-01 GMT')он все равно применяет смещение, поскольку оно преобразует его в местное время пользователя.
AaronLS
7
@AaronLS, если вы вынуждены использовать get*методы и нуждаетесь в том, чтобы они возвращали правильную дату / время, включая неизвестное смещение часового пояса, просто добавьте неизвестное смещение часового пояса: d = new Date('2013-01-08 GMT'); d.setMinutes(d.getMinutes() + d.getTimezoneOffset());это нормализует дату в соответствии с локалью пользователя, чтобы .get*методы возвращали ожидаемое значение. Эти .getUTC*методы затем будет неправильно, так что будьте осторожны.
zzzzBov
1
Существует разница между определением поведения для предоставления ссылки и использованием его в качестве escape, когда разработчикам не удалось правильно реализовать что-либо. И это не то же самое представление, если данные не соответствуют ожиданиям.
Dissident Rage
252

Есть несколько сумасшедших вещей, которые происходят с объектом JS DATE, который преобразует строки, например, рассмотрим следующую дату, которую вы указали

Примечание: следующие примеры могут быть или не быть ОДИН ДЕНЬ ВЫКЛ в зависимости от вашего часового пояса и текущего времени.

new Date("2011-09-24"); // Year-Month-Day
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF.

Однако, если мы изменим формат строки на месяц-день-год ...

new Date("09-24-2011");
=> // Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

Еще один странный

new Date("2011-09-24");
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF AS BEFORE.

new Date("2011/09/24"); // change from "-" to "/".
=> // Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

Мы могли бы легко изменить дефис в вашей дате "2011-09-24" при создании новой даты

new Date("2011-09-24".replace(/-/g, '\/')); // => "2011/09/24".
=> // Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

Что если бы у нас была строка с датой, например "2011-09-24T00: 00: 00"

new Date("2011-09-24T00:00:00");
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF.

Теперь измените дефис на косую черту, как и раньше; что случается?

new Date("2011/09/24T00:00:00");
// => Invalid Date

Обычно я должен управлять форматом даты 2011-09-24T00: 00: 00, так что это то, что я делаю.

new Date("2011-09-24T00:00:00".replace(/-/g, '\/').replace(/T.+/, ''));
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

ОБНОВИТЬ

Если вы предоставите отдельные аргументы для конструктора Date, вы можете получить другие полезные результаты, как описано ниже

Примечание: аргументы могут иметь тип Number или String. Я покажу примеры со смешанными значениями.

Получить первый месяц и день данного года

new Date(2011, 0); // Normal behavior as months in this case are zero based.
=> // Sat Jan 01 2011 00:00:00 GMT-0700 (MST)

Получить последний месяц и день года

new Date((2011 + 1), 0, 0); // The second zero roles back one day into the previous month's last day.
=> // Sat Dec 31 2011 00:00:00 GMT-0700 (MST)

Пример числа, строковых аргументов. Обратите внимание, что месяц - март, потому что месяцы снова начинаются с нуля.

new Date(2011, "02"); 
=> // Tue Mar 01 2011 00:00:00 GMT-0700 (MST)

Если мы делаем то же самое, но с нулевым днем, мы получаем что-то другое.

new Date(2011, "02", 0); // again the zero roles back from March to the last day of February.
=> // Mon Feb 28 2011 00:00:00 GMT-0700 (MST)

Добавление нулевого дня к любому аргументу года и месяца приведет к получению последнего дня предыдущего месяца. Если вы продолжите с отрицательными числами, вы можете продолжить откат на другой день

new Date(2011, "02", -1);
=> // Sun Feb 27 2011 00:00:00 GMT-0700 (MST)
SoEzPz
источник
12
Это на самом деле помогло мне лучше всего. Я только добавил .replace (/ - / g, '\ /'). Replace (/ T. + /, '') В конец моих данных, когда я сделал новую дату. Супер просто!
Девин Прежан
64
Вау - JavaScript ужасно противоречив.
psparrow
2
Вызовы .replace () очень помогли в этот вечер.
отказаться от
2
да, я проверил все это, и это действительно странно.
Чинтан Адатия
27
Все это происходит из-за поведения базового Date.parse (), пытающегося следовать ISO 8601. Когда строка даты соответствует формату гггг-мм-дд, предполагается, что это ISO 8601 с неявным UTC 00:00. Когда строка отклоняется от формата (например, mm-dd-yyyy или косая черта вместо дефиса), она возвращается к более слабому анализатору согласно RFC 2822, который использует местное время, когда часовой пояс отсутствует. По общему признанию, это все будет довольно загадочным для обычного человека.
Мизстик
71

Чтобы нормализовать дату и устранить нежелательное смещение (проверено здесь: https://jsfiddle.net/7xp1xL5m/ ):

var doo = new Date("2011-09-24");
console.log(  new Date( doo.getTime() + Math.abs(doo.getTimezoneOffset()*60000) )  );
// Output: Sat Sep 24 2011 00:00:00 GMT-0400 (Eastern Daylight Time)

Это также выполняет то же самое и относится к @tpartee (протестировано здесь: https://jsfiddle.net/7xp1xL5m/1/ ):

var doo = new Date("2011-09-24");
console.log( new Date( doo.getTime() - doo.getTimezoneOffset() * -60000 )  );
AaronLS
источник
Это помогло мне - мне пришлось работать с датами из API, а затем сортировать / сравнивать их, поэтому лучше всего просто добавить смещение часового пояса.
Чакеда
Это работало для меня, за исключением того, что я должен был вычесть timeZoneOffset, а не добавить его
ErikAGriffin
@ErikAGriffin Вы в положительном часовом поясе, IE GMT + 0X00 вместо GMT-0X00?
AaronLS
Я сделал нечто подобное:doo.setMinutes(doo.getMinutes() + doo.getTimezoneOffset())
Dissident Rage
2
@AaronLS Вы были на правильном пути, но немного неправильная логика. Для компенсации смещения TZ правильная логика: console.log (new Date (doo.getTime () - doo.getTimezoneOffset () * -60000)); - Знак смещения важен и не может быть исключен, но вам также нужен обратный знак для коррекции, поэтому мы умножаем смещение на -60000, чтобы применить обратный знак.
tpartee
28

Если вы хотите получить 0 часов некоторой даты в местном часовом поясе, передайте отдельные части даты Dateконструктору.

new Date(2011,08,24); // month value is 0 based, others are 1 based.
lincolnk
источник
26

Просто хочу добавить, что, очевидно, добавление пробела в конце строки будет использовать UTC для создания.

new Date("2016-07-06")
> Tue Jul 05 2016 17:00:00 GMT-0700 (Pacific Daylight Time)

new Date("2016-07-06 ")
> Wed Jul 06 2016 00:00:00 GMT-0700 (Pacific Daylight Time)

Изменить: это не рекомендуемое решение, просто альтернативный ответ. Пожалуйста, не используйте этот подход, так как очень неясно, что происходит. Есть несколько способов, которыми кто-то мог бы реорганизовать это случайно, вызывая ошибку.

Кайл Шрейдер
источник
Для примера с пробелом в конце консоль возвращает «Недопустимая дата = $ 2»
Брайан Риск
1
работает очень хорошо! новая дата (data.Date + "") .toLocaleDateString ("en-US")
Накрес
Чтобы быть справедливым, это был просто альтернативный ответ, и это не рекомендуемое решение.
Кайл Шрэйдер
25

Я считаю, что это связано с настройкой часового пояса. Дата, которую вы создали, по Гринвичу, а по умолчанию - полночь, но ваш часовой пояс - EDT, поэтому он вычитает 4 часа. Попробуйте это, чтобы проверить:

var doo = new Date("2011-09-25 EDT");
FishBasketGordo
источник
3
Это лучший ответ здесь. + 1 миллион за использование встроенных строк локализации часового пояса вместо программного преобразования.
blearn
2
Это помогает. Это работает так: $ scope.dat = new Date (datestring + 'EDT'). Обратите внимание на разницу между EDT и EST: ссылка
Weihui Guo
Я не знаю, что происходит за кулисами, но это работает отлично.
the_haystacker
Это, я бы сказал, самый простой из ответов и меньше переформатирования кода.
Майкл
Спасибо, я считаю лучший способ для меня.
Джандерсон Константино
11

Ваша проблема конкретно с часовым поясом. Обратите внимание GMT-0400: вы на 4 часа отстали от GMT. Если вы добавите 4 часа к отображаемой дате / времени, вы получите ровно полночь 2011/09/24. toUTCString()Вместо этого используйте метод, чтобы получить строку GMT:

var doo = new Date("2011-09-24");
console.log(doo.toUTCString());
Алекс Г
источник
7

Это, вероятно, не очень хороший ответ, но я просто хочу поделиться своим опытом с этой проблемой.

Мое приложение глобально использует дату utc в формате «ГГГГ-ММ-ДД», в то время как используемый мной плагин datepicker принимает только дату js, мне трудно учитывать и utc, и js. Поэтому, когда я хочу передать отформатированную дату «ГГГГ-ММ-ДД» в свой указатель даты, я сначала преобразовываю ее в формат «ММ / ДД / ГГГГ», используя moment.js или все, что вам нравится, и дата, отображаемая на устройстве выбора даты, теперь верный. Для вашего примера

var d = new Date('2011-09-24'); // d will be 'Fri Sep 23 2011 20:00:00 GMT-0400 (EDT)' for my lacale
var d1 = new Date('09/24/2011'); // d1 will be 'Sat Sep 24 2011 00:00:00 GMT-0400 (EDT)' for my lacale

Видимо d1 это то, что я хочу. Надеюсь, это будет полезно для некоторых людей.

Цзе Чжан
источник
1
Просто переключение форматов, как вы сделали, работал для меня так же. Так странно.
января
5

Это через меня за цикл, +1 на ответ zzzBov. Вот полное преобразование даты, которая работала для меня, используя методы UTC:

//myMeeting.MeetingDate = '2015-01-30T00:00:00'

var myDate = new Date(myMeeting.MeetingDate);
//convert to JavaScript date format
//returns date of 'Thu Jan 29 2015 19:00:00 GMT-0500 (Eastern Standard Time)' <-- One Day Off!

myDate = new Date(myDate.getUTCFullYear(), myDate.getUTCMonth(), myDate.getUTCDate());
//returns date of 'Fri Jan 30 2015 00:00:00 GMT-0500 (Eastern Standard Time)' <-- Correct Date!
cmartin
источник
4

Это значит 2011-09-24 00:00:00 GMT, и так как вы находитесь GMT -4, это будет20:00 предыдущий день.

Лично я понимаю 2011-09-24 02:00:00, потому что я живу в GMT +2.

pimvdb
источник
3

Хотя в случае OP временным поясом является EDT, нет гарантии, что пользователь, выполняющий ваш сценарий, будет находиться в часовом поясе EDT, поэтому жесткое кодирование смещения не обязательно будет работать. Решение, которое я нашел, разбивает строку даты и использует отдельные значения в конструкторе Date.

var dateString = "2011-09-24";
var dateParts = dateString.split("-");
var date = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]);

Обратите внимание, что вы должны учитывать еще одну причуду JS: месяц начинается с нуля.

Брайан Риск
источник
2

Именно с этой проблемой я столкнулся, когда мой клиент находился в Атлантическом стандартном времени. Значение даты, полученное клиентом, было «2018-11-23» и когда код передавал его в new Date("2018-11-23")выходные данные для клиента, было за предыдущий день. Я создал служебную функцию, как показано во фрагменте, который нормализовал дату, давая клиенту ожидаемую дату.

date.setMinutes(date.getMinutes() + date.getTimezoneOffset());

var normalizeDate = function(date) {
  date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
  return date;
};

var date = new Date("2018-11-23");

document.getElementById("default").textContent = date;
document.getElementById("normalized").textContent = normalizeDate(date);
<h2>Calling new Date("2018-11-23")</h2>
<div>
  <label><b>Default</b> : </label>
  <span id="default"></span>
</div>
<hr>
<div>
  <label><b>Normalized</b> : </label>
  <span id="normalized"></span>
</div>

Габриэль Гейтс
источник
2

если вы просто хотите убедиться, что отдельные части даты остаются одинаковыми для целей отображения, * это работает, даже когда я меняю часовой пояс:

var doo = new Date("2011-09-24 00:00:00")

просто добавьте туда нули.

В моем коде я делаю это:

let dateForDisplayToUser = 
  new Date( `${YYYYMMDDdateStringSeparatedByHyphensFromAPI} 00:00:00` )
  .toLocaleDateString( 
    'en-GB', 
    { day: 'numeric', month: 'short', year: 'numeric' }
  )

И я переключаю часовой пояс на моем компьютере, и дата остается той же, что и в строке даты гггг-мм-дд, которую я получаю из API.

Но я что-то упускаю / это плохая идея?

* по крайней мере, в хроме. Это не работает в Safari! на момент написания статьи

Тимоти Митчелл
источник
Когда вы делаете .toISOString(), это идет 1 день назад.
vivek_23
new Date('2019/11/18 05:30:00').toISOString();работал для меня
vivek_23
1

Лучший способ справиться с этим без использования дополнительных методов преобразования,

 var mydate='2016,3,3';
 var utcDate = Date.parse(mydate);
 console.log(" You're getting back are 20.  20h + 4h = 24h :: "+utcDate);

Теперь просто добавьте GMT ​​в свою дату, или вы можете добавить его.

 var  mydateNew='2016,3,3'+ 'GMT';
 var utcDateNew = Date.parse(mydateNew);
 console.log("the right time that you want:"+utcDateNew)

Live: https://jsfiddle.net/gajender/2kop9vrk/1/

Гаджендер Сингх
источник
1

Я столкнулся с такой проблемой, как эта. Но моя проблема была смещена при получении даты из базы данных.

это указано в базе данных и в формате UTC.

2019-03-29 19: 00: 00.0000000 +00: 00

Поэтому, когда я получаю информацию из базы данных и проверяю дату, она добавляет смещение и отправляет обратно в javascript.

введите описание изображения здесь

Это добавляет +05: 00, потому что это мой часовой пояс сервера. Мой клиент находится в другом часовом поясе +07: 00.

2019-03-28T19: 00: 00 + 05: 00 // это то, что я получаю в JavaScript.

Так вот мое решение, что я делаю с этой проблемой.

var dates = price.deliveryDate.split(/-|T|:/);
var expDate = new Date(dates[0], dates[1] - 1, dates[2], dates[3], dates[4]);
var expirationDate = new Date(expDate);

Поэтому, когда дата приходит с сервера и имеет смещение сервера, я делю дату и удаляю смещение сервера, а затем преобразую в дату. Это решает мою проблему.

Ушмаан Али
источник
1

если вам нужно простое решение для этого, смотрите:

new Date('1993-01-20'.split('-')); 

введите описание изображения здесь

Себастьян Маркос
источник
0

Вы используете формат строки даты ISO, который, согласно этой странице , приводит к построению даты с использованием часового пояса UTC:

Примечание: синтаксический анализ строк даты с помощью конструктора Date (и Date.parse, они эквивалентны) настоятельно не рекомендуется из-за различий и несоответствий в браузере. Поддержка строк формата RFC 2822 только по соглашению. Поддержка форматов ISO 8601 отличается тем, что строки, содержащие только дату (например, «1970-01-01»), обрабатываются как UTC, а не локально.

Если вы форматируете текст по-другому, например "Jan 01 1970", тогда (по крайней мере, на моем компьютере) он использует ваш местный часовой пояс.

Пол Винц
источник
0

Попытка добавить мои 2 цента к этой теме (уточняю ответ @ paul-wintz).

Сдается мне, что когда конструктор Date получает строку, которая соответствует первой части формата ISO 8601 (часть даты), он выполняет точное преобразование даты в часовом поясе UTC с 0 временем. Когда эта дата конвертируется в местное время, может произойти сдвиг даты, если полночь UTC является более ранней датой в местном часовом поясе.

new Date('2020-05-07')
Wed May 06 2020 20:00:00 GMT-0400 (Eastern Daylight Time)

Если строка даты имеет любой другой «более свободный» формат (использует «/» или дата / месяц не дополняется нулем), она создает дату в местном часовом поясе, поэтому проблема смещения даты отсутствует.

new Date('2020/05/07')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-5-07')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-5-7')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-05-7')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)

Итак, одно быстрое исправление, как упомянуто выше, состоит в замене «-» на «/» в вашей отформатированной в ISO строке только для даты.

new Date('2020-05-07'.replace('-','/'))
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
Флорин Д
источник
0

Храня yyyy-mm-ddв формате MySql Date, вы должны сделать следующее:

const newDate = new Date( yourDate.getTime() + Math.abs(yourDate.getTimezoneOffset()*60000) );
console.log(newDate.toJSON().slice(0, 10)); // yyyy-mm-dd
Пауло Гимарайнш
источник
-1

Ваш журнал выводит GMT, поэтому вы хотите указать свой часовой пояс:

var doo = new Date("2011-09-24 EST");
bmacx7
источник
3
На этот вопрос уже есть много ответов. Если вы все равно хотите ответить на вопрос, вам следует упомянуть что-то новое, чего нет в других ответах. Верхний ответ уже объясняет проблему с часовым поясом гораздо более подробно.
Кэлвин Годфри
Этот ответ почти такой же, как stackoverflow.com/a/7556642/8828658
каменный паукообразный
Кого волнует, если его объяснение более глубоко ... его код все еще отличается от моего. Мой намного проще. И да каменный паукообразный ты прав. Виноват.
bmacx7
-3

не обращайте внимания, не заметили GMT -0400, из-за которого дата была вчера

Вы можете попытаться установить время по умолчанию 12:00:00

ChrisH
источник
Да, я был немного быстр с моим ответом, извините за это. Пересмотрел мой ответ.
ChrisH
-3

Следующее сработало для меня -

    var doo = new Date("2011-09-24").format("m/d/yyyy");
Venu
источник
Это все равно не будет работать, пока вы не возитесь с часовым поясом.
Гар