Отображение даты / времени в формате локали пользователя и смещения времени

Я хочу, чтобы сервер всегда отображал даты в формате UTC в формате HTML, а JavaScript-код на клиентском сайте преобразовывал его в местный часовой пояс пользователя.

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

18 ответов

Решение

Кажется, самый надежный способ начать с даты UTC - это создать новую Date возражать и использовать setUTC… методы, чтобы установить его на дату / время, которое вы хотите.

Тогда различные toLocale…String методы обеспечат локализованный вывод.

Пример:

// This would come from the server.
// Also, this whole block could probably be made into an mktime function.
// All very bare here for quick grasping.
d = new Date();
d.setUTCFullYear(2004);
d.setUTCMonth(1);
d.setUTCDate(29);
d.setUTCHours(2);
d.setUTCMinutes(45);
d.setUTCSeconds(26);

console.log(d);                        // -> Sat Feb 28 2004 23:45:26 GMT-0300 (BRT)
console.log(d.toLocaleString());       // -> Sat Feb 28 23:45:26 2004
console.log(d.toLocaleDateString());   // -> 02/28/2004
console.log(d.toLocaleTimeString());   // -> 23:45:26

Некоторые ссылки:

Для новых проектов просто используйте moment.js

Этот вопрос довольно старый, поэтому moment.js в то время не существовало, но для новых проектов он значительно упрощает подобные задачи.

Лучше всего проанализировать вашу строку даты из UTC следующим образом (создайте совместимую с ISO-8601 строку на сервере, чтобы получить согласованные результаты во всех браузерах):

var m = moment("2013-02-08T09:30:26Z");

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

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

m.format('LLL') // Returns "February 8 2013 8:30 AM" on en-us

Чтобы преобразовать объект moment.js в другой часовой пояс (т. Е. Ни в локальный, ни в UTC), вам потребуется расширение time.js для часового пояса. На этой странице также есть несколько примеров, она довольно проста в использовании.

Ты можешь использовать new Date().getTimezoneOffset()/60 для часового пояса. Также есть toLocaleString() метод отображения даты с использованием локали пользователя.

Вот весь список: Работа с датами

В JS нет простых и кроссплатформенных способов форматирования локального времени даты, кроме преобразования каждого свойства, как упомянуто выше.

Вот быстрый взлом, который я использую, чтобы получить локальный YYYY-MM-DD. Обратите внимание, что это взлом, так как конечная дата не будет иметь правильный часовой пояс (поэтому вы должны игнорировать часовой пояс). Если мне нужно что-то еще, я использую moment.js.

var d = new Date();    
d = new Date(d.getTime() - d.getTimezoneOffset() * 60000)
var yyyymmdd = t.toISOString().slice(0,0); 
// 2017-05-09T08:24:26.581Z (but this is not UTC)

D.getTimezoneOffset() возвращает смещение часового пояса в минутах, а d.getTime() - в мс, следовательно, x 60,000.

2021 - вы можете использовать встроенный в браузер Intl.DateTimeFormat

      const utcDate = new Date(Date.UTC(2020, 11, 20, 3, 23, 16, 738));
console.log(new Intl.DateTimeFormat().format(utcDate));
// expected output: "21/04/2021", my locale is Switzerland

Ниже прямо из документации:

      const date = new Date(Date.UTC(2020, 11, 20, 3, 23, 16, 738));
// Results below assume UTC timezone - your results may vary

// Specify default date formatting for language (locale)
console.log(new Intl.DateTimeFormat('en-US').format(date));
// expected output: "12/20/2020"
    
// Specify default date formatting for language with a fallback language (in this case Indonesian)
console.log(new Intl.DateTimeFormat(['ban', 'id']).format(date));
// expected output: "20/12/2020"
    
// Specify date and time format using "style" options (i.e. full, long, medium, short)
console.log(new Intl.DateTimeFormat('en-GB', { dateStyle: 'full', timeStyle: 'long' }).format(date));
// Expected output "Sunday, 20 December 2020 at 14:23:16 GMT+11"

После того, как вы создали свой объект даты, вот фрагмент для преобразования:

Функция принимает отформатированный в формате UTC объект Date и строку формата.
Вам понадобится Date.strftime прототип.

function UTCToLocalTimeString(d, format) {
    if (timeOffsetInHours == null) {
        timeOffsetInHours = (new Date().getTimezoneOffset()/60) * (-1);
    }
    d.setHours(d.getHours() + timeOffsetInHours);

    return d.strftime(format);
}

// new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]])
var serverDate = new Date(2018, 5, 30, 19, 13, 15); // just any date that comes from server
var serverDateStr = serverDate.toLocaleString("en-US", {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric',
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
})
var userDate = new Date(serverDateStr + " UTC");
var locale = window.navigator.userLanguage || window.navigator.language;

var clientDateStr = userDate.toLocaleString(locale, {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric'
});

var clientDateTimeStr = userDate.toLocaleString(locale, {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric',
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
});

console.log("Server UTC date: " + serverDateStr);
console.log("User's local date: " + clientDateStr);
console.log("User's local date&time: " + clientDateTimeStr);

Вот что я использовал в прошлых проектах:

var myDate = new Date();
var tzo = (myDate.getTimezoneOffset()/60)*(-1);
//get server date value here, the parseInvariant is from MS Ajax, you would need to do something similar on your own
myDate = new Date.parseInvariant('<%=DataCurrentDate%>', 'yyyyMMdd hh:mm:ss');
myDate.setHours(myDate.getHours() + tzo);
//here you would have to get a handle to your span / div to set.  again, I'm using MS Ajax's $get
var dateSpn = $get('dataDate');
dateSpn.innerHTML = myDate.localeFormat('F');

Я до сих пор смешиваю ответы и добавляю их, потому что мне пришлось прочитать все из них и некоторое время дополнительно исследовать, чтобы отобразить строку даты и времени из db в формате локального часового пояса пользователя.

Строка datetime взята из базы данных python/django в формате: 2016-12-05T15:12:24.215Z

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

Python / Django: отправить язык браузера запроса в качестве параметра контекста:

language = request.META.get('HTTP_ACCEPT_LANGUAGE')
return render(request, 'cssexy/index.html', { "language": language })

HTML: напишите это в скрытом вводе:

<input type="hidden" id="browserlanguage" value={{ language }}/>

JavaScript: получить значение скрытого ввода, например, en-GB,en-US;q=0,8,en;q=0,6/, а затем выбрать первый язык в списке только с помощью замены и регулярного выражения

const browserlanguage = document.getElementById("browserlanguage").value;
var defaultlang = browserlanguage.replace(/(\w{2}\-\w{2}),.*/, "$1");

JavaScript: преобразовать в datetime и отформатировать его:

var options = { hour: "2-digit", minute: "2-digit" };
var dt = (new Date(str)).toLocaleDateString(defaultlang, options);

Смотрите: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString

Результат (язык браузера en-gb): 12.05.2016, 14:58

С датой из кода PHP я использовал что-то вроде этого..

function getLocalDate(php_date) {
  var dt = new Date(php_date);
  var minutes = dt.getTimezoneOffset();
  dt = new Date(dt.getTime() + minutes*60000);
  return dt;
}

Мы можем назвать это так

var localdateObj = getLocalDate('2015-09-25T02:57:46');

.getTimezoneOffset() Метод сообщает о смещении часового пояса в минутах, считая "запад" от часового пояса GMT/UTC, что приводит к значению смещения, которое отрицательно по отношению к тому, к которому обычно привыкли. (Например, время в Нью-Йорке будет составлять +240 минут или +4 часа)

Чтобы получить нормальное смещение часового пояса в часах, вам нужно использовать:

var timeOffsetInHours = -(new Date()).getTimezoneOffset()/60

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

Лучшее решение, с которым я столкнулся, - это создать [time display="llll" datetime="UTC TIME" /] и использовать javascript (jquery) для анализа и отображения его относительно времени пользователя.

http://momentjs.com/ Moment.js

будет отображать время красиво.

Вы можете использовать следующее, которое сообщает смещение часового пояса от GMT в минутах:

new Date().getTimezoneOffset();

Примечание: - эта функция возвращает отрицательное число.

Чтобы преобразовать дату в локальную дату, используйте метод toLocaleDateString().

var date = (new Date(str)).toLocaleDateString(defaultlang, options);

Чтобы преобразовать время в местное время, используйте метод toLocaleTimeString().

var time = (new Date(str)).toLocaleTimeString(defaultlang, options);

getTimeZoneOffset() и toLocaleString хороши для базовой работы с датами, но если вам нужна поддержка реального часового пояса, посмотрите mde's TimeZone.js.

В ответе на этот вопрос обсуждается еще несколько вариантов.

Очень старый вопрос, но, возможно, это поможет кому-то наткнуться на это. Код ниже форматирует строку даты ISO8601 в удобном для человека формате, соответствующем часовому поясу и локали пользователя. Адаптируйте по мере необходимости. Например: для вашего приложения важны ли часы, минуты, секунды для отображения пользователю для дат более 1 дня, 1 недели, 1 месяца, 1 года или чего-то еще?

Также, в зависимости от реализации вашего приложения, не забывайте периодически выполнять повторный рендеринг. (В моем коде ниже по крайней мере каждые 24 часа).

      export const humanFriendlyDateStr = (iso8601) => {

  // Examples (using Node.js):

  // Get an ISO8601 date string using Date()
  // > new Date()
  // 2022-04-08T22:05:18.595Z

  // If it was earlier today, just show the time:
  // > humanFriendlyDateStr('2022-04-08T22:05:18.595Z')
  // '3:05 PM'

  // If it was during the past week, add the day:
  // > humanFriendlyDateStr('2022-04-07T22:05:18.595Z')
  // 'Thu 3:05 PM'

  // If it was more than a week ago, add the date
  // > humanFriendlyDateStr('2022-03-07T22:05:18.595Z')
  // '3/7, 2:05 PM'

  // If it was more than a year ago add the year
  // > humanFriendlyDateStr('2021-03-07T22:05:18.595Z')
  // '3/7/2021, 2:05 PM'

  // If it's sometime in the future return the full date+time:
  // > humanFriendlyDateStr('2023-03-07T22:05:18.595Z')
  // '3/7/2023, 2:05 PM'

  const datetime = new Date(Date.parse(iso8601))
  const now = new Date()
  const ageInDays = (now - datetime) / 86400000
  let str

  // more than 1 year old?
  if (ageInDays > 365) {
    str = datetime.toLocaleDateString([], {
      year: 'numeric',
      month: 'numeric',
      day: 'numeric',
      hour: 'numeric',
      minute: 'numeric',
    })
    // more than 1 week old?
  } else if (ageInDays > 7) {
    str = datetime.toLocaleDateString([], {
      month: 'numeric',
      day: 'numeric',
      hour: 'numeric',
      minute: 'numeric',
    })
    // more than 1 day old?
  } else if (ageInDays > 1) {
    str = datetime.toLocaleDateString([], {
      weekday: 'short',
      hour: 'numeric',
      minute: 'numeric',
    })
    // some time today?
  } else if (ageInDays > 0) {
    str = datetime.toLocaleTimeString([], {
      timeStyle: 'short',
    })
    // in the future?
  } else {
    str = datetime.toLocaleDateString([], {
      year: 'numeric',
      month: 'numeric',
      day: 'numeric',
      hour: 'numeric',
      minute: 'numeric',
    })
  }
  return str
}

Вдохновлено: https://alexwlchan.net/2020/05/human-friendly-dates-in-javascript/

Протестировано с использованием Node.js

Я использую laravel для получения данных датчиков из внутренней базы данных и обработки этой информации для отображения и построения диаграмм с использованием JavaScript. Вот подход, который я использовал для преобразованияcreated_atвремя в моем местном часовом поясе.

      ...
success: function(response){
      $('#dht_data_table').html(""); //clear table data under silent table refresh
      $.each(response.dht_data, function(key, dhtdata){ // cycle through table fetching sensor data
        // convert data recorded time in local  format
        var dht_datatimestamp = new Date(dhtdata.created_at).toLocaleString("en-US", {
                              localeMatcher: "best fit",
                              timeZoneName: "short"
                            });
...
`dht_data` is the sensor data object from the database passed via jquery response in json format.

Пример выходного результата выглядит следующим образом:

      7/3/2023, 12:38:27 PM GMT+3

С уважением к этому руководству

Не знаю, как сделать локаль, но javascript - это технология на стороне клиента.

usersLocalTime = new Date();

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

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