Получить дату ISO строку без времени в JavaScript

Есть ли способ получить строку ISO нового типа даты в javascript со временем в полночь, не перестраивая новую дату с частями даты и не форматируя ее?

Я пытался это

var date = new Date();
date.setHours(0, 0, 0, 0);
document.write(date.toISOString());

и я получаю это

2017-04-20T04:00:00.000Z

Я хочу получить это

2017-04-20T00:00:00.000Z

Есть ли встроенная функция или способ, который я пытался сделать, чтобы получить желаемый результат (с перестроением объекта даты с частями даты)?

7 ответов

Решение

Просто используйте setUTCHours вместо setHours:

    var date = new Date();
    date.setUTCHours(0, 0, 0, 0);
    document.write(date.toISOString())

setHours установит время в вашем местном часовом поясе, но когда вы его отобразите, оно покажет время в UTC. Если вы просто установите его как UTC с самого начала, вы получите желаемый результат.

var date=new Date();
var corrected = date.toISOString().substring(0,10);
alert(corrected);

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

var iso = date.toISOString()
iso = iso.substr(0, iso.indexOf('T'))

Один лайнер, без сторонней библиотеки:

      const date = new Date().toISOString().split('T')[0]; // Ex: '2023-01-17'

Если вы можете жить в зависимости от великолепной библиотеки https://momentjs.com/docs/, это будет так просто:

moment().format('YYYY-MM-DD');

или же

moment().toISOString();

Проблема с большинством ответов здесь, включая ответ user11580699 , что он будет сталкиваться с преобразованиями границ дня в определенных комбинациях часового пояса и времени. т.е. вы хотите получить сегодняшнюю дату в полночь, но поскольку в системе установлен часовой пояс с отрицательным смещением, она получит завтрашнюю дату (или наоборот - получит вчерашнюю дату , если ваша система настроена на часовой пояс с положительным смещением).

Ответ user7602518 имеет правильную идею, но на самом деле он неверен для всех часовых поясов + комбинаций времени, и это только случайно для тех комбинаций, где он правильный .

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

  • Прежде всего, важно помнить, что смещения часовых поясов всегда добавляются к времени UTC, чтобы получить местное время. Подумайте об этом на простом примере: в Лондоне 12 часов дня, в Париже — 13 часов. Смещение часового пояса для Парижа равно +1, поэтому в формуле это выражается как:

            Local Time = UTC Time + Offset
    UTC Time = Local Time - Offset
    
  • Во-вторых, когда мы вызываем JS, JS получает текущее системное время, текущие настройки часового пояса системы (можно подтвердить, проверивIntl.DateTimeFormat().resolvedOptions().timeZoneв консоли JS) и использует эту информацию для преобразования времени в формате UTC (поскольку все объекты JS хранятся в формате UTC) и не преобразует результат обратно в местное время. Итак, в нашем примере, если в системе установлено ровно 1 июня в полночь по часовому поясу Парижа, вызовnew Date().toISOString()вернется2023-05-31T23:00:00.000Z

  • В-третьих, чего хочет спрашивающий, так это форматирования JS.Date.toISOString(), но без преобразования в часовой пояс UTC, т.е.2023-06-01T00:00:00.000. Поскольку все объекты даты JS изначально хранятся в формате UTC, самый простой способ сделать это — просто разрешить преобразование JS в UTC, а затем отменить его.

    • Чтобы отменить преобразование, мы должны начать с единой базы, т. е. не меняющейся в зависимости от настроек часового пояса и/или локали системы. Надежный выбор здесьDate.getTime. Когда мы звонимnew Date().getTime(), он вернет количество секунд, прошедших с начала эпохи, и эти секунды представляют собой простое целое число — без привязки к часовому поясу. Неявно предполагается, что часовой пояс — UTC, и все методы JS основаны на этом предположении. Поскольку мы хотим отменить преобразование UTC, которое уже произошло , когда JS создал объект Date, нам нужно использовать формулу для местного времени, но принимая ее обратную, то есть нам нужно вычесть обратно добавленное ранее смещение . Таким образом, мы получаем следующие формулы:

                Local Time = UTC Time - Offset 
      UTC Time = Local Time + Offset
      

Объединив все вышеперечисленное, мы можем придумать метод очень общего назначения, который преобразует объект даты JS в «строку ISO», но отформатированную в местном часовом поясе:

      // jsDateToISOLocalStr
// Converts a JS date to a "ISO-style" string (i.e. not converting to UTC Zero Offset Time)
// i.e. Suppose it is May 2, 2023 @ 4:36 AM, and we are on a system with a +10 timezone (around Australia)
// The difference between 'toISOString' builtin and jsDateToISOLocalStr is simply as thus:
// new Date().toISOString() --> '2023-05-01T18:36:31.866Z'
// jsDateToISOLocalStr()    --> '2023-05-02T04:36:31.866'
// All JS Date objects are stored as UTC, and so if a local timezone is displayed by JS, we must "convert back"
// params:
//   * d (optional) -- anything that can be parsed by JS new Date constructor
// returns -- One of the below:
//   * if d can be parsed by JS Date: an ISO-style string representation of d according to local (machine) time
//   * if d is not truthy or not passed in: an ISO-style string representation of 'right now' according to local time
//   * if d cannot be parsed by JS date (that is, when new Date(d) returns "Invalid Date"): null
export const jsDateToISOLocalStr = (d) => {
    let retVal = null;
    // We necessarily do some string parsing because JS Date doesn't parse dates consistently
    // e.g. -- new Date("2023-05-01") returns midnight at UTC,
    //         new Date("2023-05-01 ") (or any non-strict variant) returns midnight in the local timezone
    // We will force to the local time unless any time component is already in the string
    // If the total string length is less than 11, then there isn't any time component.
    const parsedInput = (typeof d === "string" || d instanceof String) && d.length < 11 ? `${d} ` : d;
    // We must not pass a date argument if we want today's date. "new Date(null)" returns the epoch (Jan 1 1970)!
    const utcDate = d ? new Date(parsedInput) : new Date();
    if (String(utcDate).toLowerCase() !== "invalid date") {
        // Conversion to UTC already took place -- now we must *undo* that
        const localTimestamp = utcDate.getTime() - utcDate.getTimezoneOffset() * 60 * 1000;
        const localDate = new Date(localTimestamp);
        // Remove the final trailing 'Z' to indicate local time
        retVal = localDate.toISOString().slice(0, -1);
    }
    return retVal;
};

Теперь мы наконец можем получить желаемый результат:

      const isoLocalDateTime = jsDateToISOLocalStr();
const isoLocalDate = isoLocalDateTime.split("T")[0];

// To write the local date set to midnight time
document.write(`${isoLocalDate}T00:00:00.000`);
// Optionally, to write the local date set to the current time
document.write(isoLocalDateTime);
// Optionally, to just write the local date with no time component
document.write(isoLocalDate);

с форматом даты-fns

      import {format} from "date-fns-tz"    
format(new Date(), 'yyyy-MM-dd')
Другие вопросы по тегам