Создать дату с установленным часовым поясом без использования строкового представления

У меня есть веб-страница с тремя выпадающими списками для дня, месяца и года. Если я использую JavaScript Date конструктор, который принимает числа, то я получаю Date объект для моего текущего часового пояса:

new Date(xiYear, xiMonth, xiDate)

Дайте правильную дату, но она думает, что дата - GMT+01:00 из-за перехода на летнее время.

Проблема здесь в том, что я тогда передаю это Date в метод Ajax, и когда дата десериализована на сервере, она была преобразована в GMT и потеряла час, который переводит день назад на единицу. Теперь я могу просто передать день, месяц и год по отдельности в метод Ajax, но, похоже, должен быть лучший путь.

Принятый ответ направил меня в правильном направлении, но только используя setUTCHours() само собой изменилось:

Apr 5th 00:00 GMT+01:00 

в

Apr 4th 23:00 GMT+01:00

Затем я также должен был установить дату UTC, месяц и год, чтобы в конечном итоге

Apr 5th 01:00 GMT+01:00

что я и хотел

31 ответ

Решение

С помощью .setUTCHours() было бы возможно фактически установить даты в UTC-времени, что позволило бы вам использовать UTC-время по всей системе.

Вы не можете установить его, используя UTC в конструкторе, если только вы не укажете строку даты.

С помощью new Date(Date.UTC(year, month, day, hour, minute, second)) Вы можете создать объект Date из определенного времени UTC.

Просто установите часовой пояс и вернитесь в соответствии

new Date().toLocaleString("en-US", {timeZone: "America/New_York"})
var d = new Date(xiYear, xiMonth, xiDate);
d.setTime( d.getTime() + d.getTimezoneOffset()*60*1000 );

Этот ответ специально разработан для исходного вопроса и не даст того ответа, который вы обязательно ожидаете. В частности, некоторые люди захотят вычесть смещение часового пояса, а не добавить его. Помните, однако, что весь смысл этого решения состоит в том, чтобы взломать объект даты javascript для конкретной десериализации, а не быть корректным во всех случаях.

Я считаю, что вам нужна функция createDateAsUTC (пожалуйста, сравните с convertDateToUTC)

function createDateAsUTC(date) {
    return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()));
}

function convertDateToUTC(date) { 
    return new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()); 
}

Я не верю, что это возможно - нет возможности установить часовой пояс для объекта Date после его создания.

И в некотором смысле это имеет смысл - концептуально (если, возможно, не в реализации); за http://en.wikipedia.org/wiki/Unix_timestamp (выделено мной):

Время Unix, или время POSIX, представляет собой систему для описания моментов во времени, определяемых как количество секунд, прошедших с полуночного координированного универсального времени (UTC) четверга, 1 января 1970 года.

После того, как вы его построите, он будет представлять определенную точку в "реальном" времени. Часовой пояс имеет значение только тогда, когда вы хотите преобразовать этот абстрактный момент времени в удобочитаемую строку.

Таким образом, имеет смысл, что вы сможете изменить только фактическое время, которое Date представляет в конструкторе. К сожалению, кажется, что нет никакого способа передать в явном часовом поясе - и конструктор, который вы вызываете (возможно, правильно), переводит ваши "локальные" переменные времени в GMT, когда он канонически сохраняет их - поэтому нет никакого способа использовать int, int, int конструктор для времени по Гринвичу.

С другой стороны, тривиально просто использовать конструктор, который принимает String. Вам даже не нужно конвертировать числовой месяц в строку (по крайней мере, в Firefox), поэтому я надеялся, что наивная реализация сработает. Тем не менее, после его тестирования он успешно работает в Firefox, Chrome и Opera, но не работает в Konqueror ("Неверная дата"), Safari ("Неверная дата") и IE ("NaN"). Я полагаю, у вас просто есть массив поиска для преобразования месяца в строку, например так:

var months = [ '', 'January', 'February', ..., 'December'];

function createGMTDate(xiYear, xiMonth, xiDate) {
   return new Date(months[xiMonth] + ' ' + xiDate + ', ' + xiYear + ' 00:00:00 GMT');
}

Я знаю, что это старо, но если это поможет, вы можете использовать момент и часовой пояс. Если вы не видели их, посмотрите.

http://momentjs.com/timezone/

http://momentjs.com/

две действительно удобные библиотеки управления временем

Если вы хотите решить немного другую, но связанную проблему создания объекта Javascript Date из года, месяца, дня,..., включая часовой пояс - то есть, если вы хотите проанализировать строку в Date - тогда вы по-видимому, нужно сделать невероятно сложный танец

// parseISO8601String : string -> Date
// Parse an ISO-8601 date, including possible timezone,
// into a Javascript Date object.
//
// Test strings: parseISO8601String(x).toISOString()
// "2013-01-31T12:34"              -> "2013-01-31T12:34:00.000Z"
// "2013-01-31T12:34:56"           -> "2013-01-31T12:34:56.000Z"
// "2013-01-31T12:34:56.78"        -> "2013-01-31T12:34:56.780Z"
// "2013-01-31T12:34:56.78+0100"   -> "2013-01-31T11:34:56.780Z"
// "2013-01-31T12:34:56.78+0530"   -> "2013-01-31T07:04:56.780Z"
// "2013-01-31T12:34:56.78-0330"   -> "2013-01-31T16:04:56.780Z"
// "2013-01-31T12:34:56-0330"      -> "2013-01-31T16:04:56.000Z"
// "2013-01-31T12:34:56Z"          -> "2013-01-31T12:34:56.000Z"
function parseISO8601String(dateString) {
    var timebits = /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2})(?::([0-9]*)(\.[0-9]*)?)?(?:([+-])([0-9]{2})([0-9]{2}))?/;
    var m = timebits.exec(dateString);
    var resultDate;
    if (m) {
        var utcdate = Date.UTC(parseInt(m[1]),
                               parseInt(m[2])-1, // months are zero-offset (!)
                               parseInt(m[3]),
                               parseInt(m[4]), parseInt(m[5]), // hh:mm
                               (m[6] && parseInt(m[6]) || 0),  // optional seconds
                               (m[7] && parseFloat(m[7])*1000) || 0); // optional fraction
        // utcdate is milliseconds since the epoch
        if (m[9] && m[10]) {
            var offsetMinutes = parseInt(m[9]) * 60 + parseInt(m[10]);
            utcdate += (m[8] === '+' ? -1 : +1) * offsetMinutes * 60000;
        }
        resultDate = new Date(utcdate);
    } else {
        resultDate = null;
    }
    return resultDate;
}

Таким образом, вы создаете "время UTC", используя дату без часового пояса (чтобы вы знали, в каком он находится, а именно "локаль" UTC, а не локальное по умолчанию), а затем вручную применяете указанное смещение часового пояса.

Разве не было бы неплохо, если бы кто-то на самом деле думал об объекте даты Javascript более пяти минут...

d = new Date();
utc = d.getTime() + (d.getTimezoneOffset() * 60000);
nd = new Date(utc + (3600000*offset));

offset value base on which location time zone you would like to set 
For India offset value +5.5,
New York offset value -4,
London offset value +1

для всех смещений местоположения Wiki Список смещений времени UTC

// My clock 2018-07-25, 00:26:00 (GMT+7)
let date = new Date(); // 2018-07-24:17:26:00 (Look like GMT+0)
const myTimeZone = 7; // my timeZone 
// my timeZone = 7h = 7 * 60 * 60 * 1000 (millisecond);
// 2018-07-24:17:26:00 = x (milliseconds)
// finally, time in milliseconds (GMT+7) = x + myTimezone 
date.setTime( date.getTime() + myTimeZone * 60 * 60 * 1000 );
// date.toISOString() = 2018-07-25, 00:26:00 (GMT+7)

Решение одной линии

new Date(new Date(1422524805305).getTime() - 330*60*1000)

Вместо 1422524805305 используйте метку времени в миллисекундах. Вместо 330 используйте смещение часового пояса в минутах по отношению к. Время по Гринвичу (например, Индия +5:30 - 5*60+30 = 330 минут)

getTimeZoneOffset является минусом для UTC + z.

var d = new Date(xiYear, xiMonth, xiDate);
if(d.getTimezoneOffset() > 0){
    d.setTime( d.getTime() + d.getTimezoneOffset()*60*1000 );
}

Это может помочь кому-то, поставить UTC в конце того, что вы передаете новому конструктору

По крайней мере в хроме можно сказать var date = new Date("2014-01-01 11:00:00 UTC")

Самый простой способ найти правильную дату - использовать datejs.

http://www.datejs.com/

Я получаю свои даты через Ajax в следующем формате: "2016-01-12T00:00:00"

var yourDateString = '2016-01-12T00:00:00';
var yourDate = new Date(yourDateString);
console.log(yourDate);
if (yourDate.getTimezoneOffset() > 0){
    yourDate = new Date(yourDateString).addMinutes(yourDate.getTimezoneOffset());
}
console.log(yourDate);

Консоль будет читать:

Пн Ян 11 2016 19:00:00 GMT-0500 (Восточное стандартное время)

Вт Янв 2016 2016 00:00:00 GMT-0500 (Восточное стандартное время)

https://jsfiddle.net/vp1ena7b/3/

"AddMinutes" происходит от datejs, вы, вероятно, могли бы сделать это в чистом js самостоятельно, но у меня уже был datejs в моем проекте, поэтому я нашел способ использовать его, чтобы получить правильные даты.

Я думал, что это может помочь кому-то...

Вот функция, которую вы можете использовать для получения объекта даты:

      const getUTCDate = (date) => {
    const d = new Date(date);
    const utcDate = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
    return utcDate;
}

const string = '1930-08-12T00:00:00.000000Z';

const utcDate = getUTCDate(string);

// returns Tue Aug 12 1930 00:00:00 GMT-0800 (Pacific Daylight Time)

Этот код вернет ваш объект Date, отформатированный в часовом поясе браузера.

Date.prototype.timezone = function () {
    this.setHours(this.getHours() + (new Date().getTimezoneOffset() / 60));
    return this;
}

Любой пробег в

var d = new Date(xiYear, xiMonth, xiDate).toLocaleString();
      const date = new Date("2020-12-16 17:45:00 UTC");

Работает отлично.

На самом деле это совсем не сложно сделать, но, конечно же, придумать решение не интуитивно. Здесь есть несколько действительно запутанных ответов (хотя и хороших). Вот что я придумал, чтобы убедиться, что временные метки моего сервера совпадают с моими локальными временными метками, независимо от того, в каком часовом поясе оказался мой развернутый сервер.

(CET = Central European Timezone, который просто является моим личным часовым поясом; вы можете получить смещение любого данного часового пояса, вычислить его и даже сделать его аргументом, если хотите, но для моей цели мне просто нужно было получить мои даты чтобы все были в едином желаемом согласованном часовом поясе.)

          const convertDateToCET = function(date) {
        date = new Date(date)
        // let startTime = date.getTime();
        const cetOffset = -120; // this is the number you get from running 
        // `(new Date()).getTimezoneOffset()` if you're on a machine in CET
        const offsetFromCET = (date.getTimezoneOffset() - cetOffset);
        const cetMillsecondOffset = ( cetOffset* 60 * 1000);
        date = new Date( date.getTime() - cetMillsecondOffset ) 
        // let endTime = date.getTime()
        // console.log("updated date from",startTime,"to",endTime)
        return date;
    },

Используя это, вы просто проводите время так, как вы ожидаете, например

          let myDate = new Date("12-4-2021")
    myDate.setHour(14)
    myDate.setMinute(30)
    // now myDate is 2:30pm, December 4th, 2021, in whatever the timezone the machine of code running happens to be in
    myDate = convertDateToCET(myDate)
    // now myDate will show up as 2:30pm, Dec 4th, 2021, mapped into your local timezone
    // so, if you're in the UK, and one hour behind CET, myDate is now 1:30pm, Dec 4th, 2021

Ключ здесь date.getTimezoneOffset(). Если вы на самом деле находитесь в CET, это число будет -120, и поэтому он отменяется без разницы (поэтому CET приводит к выходу CET). Если вы находитесь в Великобритании, на один час позже среднеевропейского времени, это будет -60, что значит -60 + 120 = +60что приводит к изменению времени ввода на один час и так далее .

Вероятно, имеет смысл преобразовать все и использовать все в формате UTC для такого случая, но, учитывая, что все мое время ввода находится в CET, и я изначально разработал систему на основе того, как все выглядело локально на моей машине, эта утилита позволил мне преобразовать существующий код, просто вызвав эту функцию в нескольких ключевых местах.

Внимание: убедитесь, что вы не применяете этот вызов функции несколько раз в одну и ту же дату, так как вы будете повторно применять смещение несколько раз, отбрасывая его!

Мне было трудно это понять:

      new Date('2023-06-16')
// Date Mon Jun 20 2022 17:00:00 GMT-0700 (heure d’été du Pacifique nord-américain) 

отличается от

      new Date('2023-06-16 00:00:00')
// Date Tue Jun 21 2022 00:00:00 GMT-0700 (heure d’été du Pacifique nord-américain)

У меня была аналогичная проблема с выбором даты. Мои исследования привели к очень простому решению без каких-либо дополнительных библиотек или жестко запрограммированных множителей.

Основная информация:

  1. ISO - это предпочтительный стандарт даты Javascript. Предположим, что утилиты даты, скорее всего, будут возвращать значения даты в этом формате.
    • В моем средстве выбора даты дата отображается в локализованном формате: мм / дд / гггг

    • Однако он возвращает значение даты в формате ISO: гггг-мм-дд

      //Select "08/12/2020" in Date Picker date_input 
      
      var input = $('#date_input').val();  //input: 2020-08-12
      
  1. Date.getTimezoneOffset() возвращает смещение в минутах.

Примеры:

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

var input = $('#date_input').val();  //input: 2020-08-12
var date = new Date(input);          //This get interpreted as an ISO date, already in UTC
//date:                             Tue Aug 11 2020 20:00:00 GMT-0400 (Eastern Daylight Time)
//date.toUTCString():               Wed, 12 Aug 2020 00:00:00 GMT
//date.toLocaleDateString('en-US'):       8/11/2020

Использование формата строки даты, отличного от стандарта ISO, гггг-мм-дд, применяет ваш часовой пояс к дате.

var date = new Date("08/12/2020");  //This gets interpreted as local timezone
//date:                             Wed Aug 12 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
//date.toUTCString():               Wed, 12 Aug 2020 04:00:00 GMT
//date.toLocaleDateString('en-US'):       8/12/2020

Решение:

Чтобы применить часовой пояс к дате, не зависящей от формата, без манипуляций со строками, используйте Date.getTimezoneOffset()с минутами. Это работает либо с исходным форматом строки даты (например, датами в формате UTC или локализованными датами). Он обеспечивает согласованный результат, который затем можно точно преобразовать в UTC для хранения или взаимодействия с другим кодом.

var input = $('#date_input').val();
var date = new Date(input);
date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
//date:                             Wed Aug 12 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
//date.toUTCString():               Wed, 12 Aug 2020 04:00:00 GMT
//date.toLocaleDateString('en-US'):       8/12/2020
                

РЕШЕНО:

Когда я создаю объект даты:

new Date(year, month, day, hour, minute)

У меня нормально работает на localhost. Когда я развертываю сервер, он ломается, потому что сервер находится в другом часовом поясе.

Я не могу использовать getTimezoneOffset(). Мне нужен часовой пояс, смещение моего дома - в зависимости от летнего/зимнего времени

// add diff minutes between myself (HOME) and server 
timezoneHomeOffset (d, tz = 'Europe/Copenhagen') {
  const utc = new Date(d.getTime())
  const dHome = new Date(d.toLocaleString('en-US', { timeZone: tz }))
  const diff = Math.round((utc - dHome) / 60000) // 60*1000 => minutes
  d.setMinutes(d.getMinutes() + diff)
  return d
}

Это отлично работало для разных часовых поясов (IST, PST, Мексика, Центральная Америка):

      let dateUtc: any = new Date(Date.parse(data.details.dateOfBirth));

dateUtc = new Date(dateUtc.getTime() + Math.abs(dateUtc.getTimezoneOffset()*60000));

console.log(dateUtc);

GMT -03:00 Пример

new Date(new Date()-3600*1000*3).toISOString();  // 2020-02-27T15:03:26.261Z

Или даже

now  = new Date().getTime()-3600*1000*3; // 1582818380528
data = new Date(now).toISOString();      // 2020-02-27T15:03:26.261Z

Вы можете использовать библиотеку, чтобы помочь изменить часовой пояс

moment-timezone

      var moment = require("moment-timezone");
const today = new Date();
var timeGet = moment(today);
timeGet.tz("Asia/Karachi").format("ha z");

это может изменить ваш часовой пояс вашего региона, вставить регион и получить реальную проблему с gmt +

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

Лучшее решение, которое я видел из этого, пришло от

http://www.codingforums.com/archive/index.php/t-19663.html

Функция печати времени

<script language="javascript" type="text/javascript">
//borrowed from echoecho
//http://www.echoecho.com/ubb/viewthread.php?tid=2362&pid=10482&#pid10482
workDate = new Date()
UTCDate = new Date()
UTCDate.setTime(workDate.getTime()+workDate.getTimezoneOffset()*60000)

function printTime(offset) {
    offset++;
    tempDate = new Date()
    tempDate.setTime(UTCDate.getTime()+3600000*(offset))
    timeValue = ((tempDate.getHours()<10) ? ("0"+tempDate.getHours()) : (""+tempDate.getHours()))
    timeValue += ((tempDate.getMinutes()<10) ? ("0"+tempDate.getMinutes()) : tempDate.getMinutes())
    timeValue += " hrs."
    return timeValue
    }
    var now = new Date()
    var seed = now.getTime() % 0xfffffff
    var same = rand(12)
</script>

Banff, Canada:
<script language="JavaScript">document.write(printTime("-7"))</script>

Пример полного кода

<html>

<head>
<script language="javascript" type="text/javascript">
//borrowed from echoecho
//http://www.echoecho.com/ubb/viewthread.php?tid=2362&pid=10482&#pid10482
workDate = new Date()
UTCDate = new Date()
UTCDate.setTime(workDate.getTime()+workDate.getTimezoneOffset()*60000)

function printTime(offset) {
offset++;
tempDate = new Date()
tempDate.setTime(UTCDate.getTime()+3600000*(offset))
timeValue = ((tempDate.getHours()<10) ? ("0"+tempDate.getHours()) : (""+tempDate.getHours()))
timeValue += ((tempDate.getMinutes()<10) ? ("0"+tempDate.getMinutes()) : tempDate.getMinutes())
timeValue += " hrs."
return timeValue
}
var now = new Date()
var seed = now.getTime() % 0xfffffff
var same = rand(12)
</script>

</head>

<body>
Banff, Canada:
<script language="JavaScript">document.write(printTime("-7"))</script>
<br>
Michigan:
<script language="JavaScript">document.write(printTime("-5"))</script>
<br>
Greenwich, England(UTC):
<script language="JavaScript">document.write(printTime("-0"))</script>
<br>
Tokyo, Japan:
<script language="JavaScript">document.write(printTime("+9"))</script>
<br>
Berlin, Germany:
<script language="JavaScript">document.write(printTime("+1"))</script>

</body>
</html>

Например, в Бразилии время по Гринвичу -3 часа. Если приложение возвращает дату и время «GMT+0» вместо часового пояса моей страны, оно отображается на 3 часа вперед, поэтому мы можем настроить это смещение с помощью пользовательской функции:

      function DateGMT( offset ){
   return new Date( new Date().getTime() + (offset * 60 * 60 * 1000) );  
}

Теперь я могу получить дату – 3 часа, используя:

      var myDate = DateGMT(-3); // Brazil is GMT-3

Боль в моем мозгу. Как получить текущую дату с часовым поясом, как на сервере с WORDPRESS в js.

      var dnow = new Date();
dnow = dnow.getTime() + dnow.getTimezoneOffset()*60*1000 + <?= get_option( 'gmt_offset' ) ?> * 60*60*1000;

Сначала нам нужно получить текущую дату. Затем нам нужно удалить смещение часового пояса пользователя. Затем мы добавляем смещение gmt со страницы параметров WordPress.

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

  const currTimezone = new Date().getTimezoneOffset(); // your timezone
  const newDateTimezone = date.getTimezoneOffset(); // date with unknown timezone

  if (currTimezone !== newDateTimezone) {
    // and below you are checking if difference should be - or +. It depends on if unknown timezone is lesser or greater than yours
    const newTimezone = (currTimezone - newDateTimezone) * (currTimezone > newDateTimezone ? 1 : -1);
    date.setTime(date.getTime() + (newTimezone * 60 * 1000));
  }

Я использовал пакет timezone-js.

var timezoneJS  = require('timezone-js');
var tzdata = require('tzdata');

::

createDate(dateObj) {
    if ( dateObj == null ) {
        return null;
    }
    var nativeTimezoneOffset = new Date().getTimezoneOffset();
    var offset = this.getTimeZoneOffset();

    // use the native Date object if the timezone matches
    if ( offset == -1 * nativeTimezoneOffset ) {
        return dateObj;
    }

    this.loadTimeZones();

    // FIXME: it would be better if timezoneJS.Date was an instanceof of Date
    //        tried jquery $.extend
    //        added hack to Fiterpickr to look for Dater.getTime instead of "d instanceof Date"
    return new timezoneJS.Date(dateObj,this.getTimeZoneName());
},

Это сработало для меня. Не уверен, что это хорошая идея.

var myDate = new Date();
console.log('myDate:', myDate);   // myDate: "2018-04-04T01:09:38.112Z"

var offset = '+5';  // e.g. if the timeZone is -5

var MyDateWithOffset = new Date( myDate.toGMTString() + offset );   

console.log('MyDateWithOffset:', MyDateWithOffset); // myDateWithOffset: "2018-04-03T20:09:38.000Z"

Другие вопросы по тегам