«Правильный» формат даты JSON


1138

Я видел так много разных стандартов для формата даты JSON:

"\"\\/Date(1335205592410)\\/\""         .NET JavaScriptSerializer
"\"\\/Date(1335205592410-0500)\\/\""    .NET DataContractJsonSerializer
"2012-04-23T18:25:43.511Z"              JavaScript built-in JSON object
"2012-04-21T18:25:43-05:00"             ISO 8601

Какой из них правильный? Или лучше? Есть ли какой-то стандарт на это?


75
В JSON нет формата даты, есть только строки, которые де-сериализатор решает сопоставить со значениями даты.

11
strings, numbers, true, false, null, objectsИarrays
Russ Cam

12
Однако встроенный в JSON объект JSON и ISO8601 содержат всю информацию, которая должна быть понятна человеку и компьютеру, и не зависят от начала компьютерной эры (1970-1-1).
Poussma

Ответы:


1851

JSON сам по себе не определяет, как даты должны быть представлены, но JavaScript делает.

Вы должны использовать формат , испускаемый Date«S toJSONметодом:

2012-04-23T18:25:43.511Z

Вот почему:

  1. Это читается человеком, но также кратко

  2. Сортирует правильно

  3. Он включает доли секунды, которые могут помочь восстановить хронологию

  4. Соответствует ISO 8601

  5. ISO 8601 был признан во всем мире уже более десяти лет.

  6. ISO 8601 одобрен W3C , RFC3339 и XKCD

При этом каждая библиотека дат, когда-либо написанная, может понимать «миллисекунды с 1970 года». Так что для легкой переносимости, ThiefMaster подходит.


32
Это также предпочтительные представления в соответствии с ECMA :JSON.stringify({'now': new Date()}) "{"now":"2013-10-21T13:28:06.419Z"}"
Стивен

11
Я бы добавил еще одну важную причину в список: он не зависит от локали. Если у вас была такая дата, как 02-03-2014, вам понадобится дополнительная информация, чтобы узнать, относится ли она к 3 февраля или 2 марта. Это зависит от того, используется ли формат США или другой формат.
Хуанал

107
upvote для упоминания и ссылки xkcd: D @ajorquera Я обычно использую моменты для этого. Я также видел проблемы с IE в этом отношении
fholzer

54
Что касается второго пункта, он не сортируется правильно после 10000 года. У нас есть почти 8000 лет, чтобы придумать новый формат, так что, вероятно, это не проблема.
Эрфа

7
На самом деле, @Erfa, так как -идет раньше, чем цифры ASCII, он будет хорошо сортироваться до 100 000 года. ; P
Бен Легжеро

128

JSON ничего не знает о датах. То, что делает .NET - это нестандартный взлом / расширение.

Я хотел бы использовать формат, который может быть легко преобразован в Dateобъект в JavaScript, то есть тот, который может быть передан new Date(...). Самый простой и, вероятно, самый переносимый формат - это отметка времени, содержащая миллисекунды с 1970 года.


3
stackoverflow.com/questions/10286385/… - давайте посмотрим, знает ли кто-нибудь, почему FF ведет себя так.
ThiefMaster

11
Если вы идете по этому пути, убедитесь, что вам не нужно иметь дело с датами ранее, чем 1970!
Бен Долман,

8
Как сказал @BenDolman, это «решение» не имеет должного отношения к датам до 1 января 1970 года (эпоха). Кроме того, существует причина, по которой ISO8601 существует в первую очередь. Здесь, на Земле, есть вещи, которые называются «часовыми поясами». Где это в миллисекундах? JSON может не иметь стандарта для дат, но даты существуют вне JSON, и для этого есть стандарт. Ответ funroll является правильным (см. также: xkcd.com/1179 ).
JoeLinux

5
Возможно, также стоит упомянуть, что (милли) секунды с 1970 года не предсказуемы для дат в будущем, потому что у нас есть дополнительные секунды . Поэтому я бы не стал использовать его для межпроцессного взаимодействия и хранения данных. Тем не менее, это удобно для внутреннего использования в программе, поскольку она может храниться в одном целом числе, что дает некоторые преимущества в производительности.
Броди Гранат

5
Временная метка Unix всегда указывается в формате UTC, вы преобразуете из своего местного часового пояса перед созданием временной метки и снова возвращаетесь в отображаемый местный часовой пояс, в этом нет никакой двусмысленности.
lkraider

46

Там нет правильного формата ; Спецификация JSON не определяет формат для обмена датами, поэтому существует так много разных способов сделать это.

Наилучшим форматом, возможно, является дата, представленная в формате ISO 8601 ( см. Википедия ); Это хорошо известный и широко используемый формат, который может обрабатываться на разных языках, что делает его очень подходящим для взаимодействия. Например, если у вас есть контроль над сгенерированным json, вы предоставляете данные другим системам в формате json, выбрав 8601 в качестве формата обмена датами.

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


2
@mlissner, но это мнение о том, какой из них лучше. ISO-8601 - это стандарт, но он не является стандартом для JSON (хотя я склонен его использовать); например, Microsoft решила не использовать его ( msdn.microsoft.com/en-us/library/… ). Лучшая практика - придерживаться одного (разумного) соглашения, что бы это ни было. Как я сказал в ответе, лучший способ справиться с этим - определить функцию полезности парсинга даты, которая может обрабатывать ожидаемые форматы. Если вы интегрируетесь с системами, которые используют разные форматы, функция должна обрабатывать каждый случай.
Расс Cam Cam

1
@RussCam, мы можем идти вперед и назад, но если кто-то спрашивает, как лучше кодировать даты в JSON, они спрашивают, как форматировать даты, когда они создают JSON (и ответ обычно ISO-8601). Вы отвечаете на противоположный вопрос: как использовать даты JSON, когда они уже сделаны (хотя ваш совет обоснован).
mlissner

1
Спецификация схемы JSON фактически говорит о том, что даты, которые проверяются схемой, должны быть в формате 8601.
gnasher729

3
@ gnasher729 у тебя есть ссылка?
Расс Кэм

@vallismortis - это черновая спецификация для определения схемы для данной структуры json, которой обмениваются стороны, а не формат для дат в спецификации json. Я собираюсь пересмотреть свой ответ, основываясь на комментариях, но, похоже, я недостаточно четко это объяснил
Russ Cam

27

Из RFC 7493 (формат сообщений I-JSON) :

I-JSON означает либо интернет-JSON, либо совместимый JSON, в зависимости от того, кого вы спрашиваете.

Протоколы часто содержат элементы данных, предназначенные для хранения временных меток или временных интервалов. РЕКОМЕНДУЕТСЯ, чтобы все такие элементы данных были выражены в виде строковых значений в формате ISO 8601, как указано в RFC 3339 , с дополнительными ограничениями, заключающимися в том, что используются прописные, а не строчные буквы, что часовой пояс должен быть включен по умолчанию, и что необязательные конечные секунды быть включенным, даже если их значение равно "00". Также РЕКОМЕНДУЕТСЯ, чтобы все элементы данных, содержащие длительности времени, соответствовали производству "продолжительности" в Приложении A RFC 3339, с такими же дополнительными ограничениями.


2
Это также формат, создаваемый Date().toISOString()и Date().toJSON(), с ограничением, которое Dateне отслеживает значение часового пояса и, следовательно, всегда выдает временные метки в Zчасовом поясе UTC ( ). Значение может быть проанализировано с помощью new Date("...")и Date.parseDate.
Серен Левборг

15

Просто для справки я видел этот формат используется:

Date.UTC(2017,2,22)

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

FWIW: Никогда не используйте секунды с эпохи в протоколе связи, ни миллисекунды с эпохи, потому что они чреваты опасностью из-за рандомизированной реализации високосных секунд (вы не представляете, правильно ли отправитель и получатель реализуют високосные секунды UTC).

В некотором роде ненависть к домашним животным, но многие люди считают, что UTC - это просто новое название для GMT - неправильно! Если ваша система не поддерживает високосные секунды, то вы используете GMT ​​(часто называемое UTC, хотя оно и неверно). Если вы полностью реализуете дополнительные секунды, вы действительно используете UTC. Будущие високосные секунды не могут быть известны; они публикуются IERS по мере необходимости и требуют постоянных обновлений. Если вы работаете с системой, которая пытается внедрить дополнительные секунды, но содержит устаревшую справочную таблицу (более распространенную, чем вы думаете), то у вас нет ни GMT, ни UTC, у вас шаткая система, претендующая на UTC.

Эти счетчики даты совместимы только в том случае, если они выражены в разбитом формате (y, m, d и т. Д.). Они НИКОГДА не совместимы в эпохальном формате. Запомни.


4
Я бы не использовал этот формат, но остальная информация, которую вы предоставили, очень полезна, спасибо!
Роберт

9

В случае сомнений просто перейдите в веб-консоль javascript современного браузера, нажав F12 (Ctrl + K в Firefox), и напишите следующее:

new Date().toISOString()

Будет выводить:

"2019-07-04T13: 33: 03.969Z"

Та-да !!


3

Я считаю, что лучшим форматом для универсального взаимодействия является не строка ISO-8601, а формат, используемый EJSON:

{ "myDateField": { "$date" : <ms-since-epoch> } }

Как описано здесь: https://docs.meteor.com/api/ejson.html

Льготы

  1. Производительность синтаксического анализа: если вы храните даты в виде строк ISO-8601, это хорошо, если вы ожидаете значение даты в этом конкретном поле, но если у вас есть система, которая должна определять типы значений без контекста, вы анализируете каждую строку для Формат даты.
  2. Нет необходимости в проверке даты : вам не нужно беспокоиться о проверке даты. Даже если строка соответствует формату ISO-8601, она не может быть реальной датой; это никогда не может произойти с датой EJSON.
  3. Однозначное объявление типа: что касается универсальных систем данных, если вы хотите сохранить строку ISO в виде строки в одном случае и реальную системную дату в другом, универсальные системы, использующие формат строки ISO-8601, не позволят этого механически (без уловок или подобных ужасных решений).

Вывод

Я понимаю, что удобочитаемый формат (строка ISO-8601) полезен и более удобен для 80% случаев использования, и, действительно, никто никогда не должен указывать не хранить свои даты в виде строк ISO-8601, если это их приложения понять, но для общепринятого транспортного формата, который должен гарантировать определенные значения, которые наверняка будут датами, как мы можем допустить двусмысленность и необходимость в такой большой проверке?


См. Этот ответ ранее в теме о том, почему миллисекунды с начала эпохи имеют такие оговорки, как неправильное вычисление високосных секунд и т. Д .: stackoverflow.com/a/42480073/190476
Судханшу Мишра

@SudhanshuMishra Предостережения, на которые вы ссылаетесь, являются общими ошибками для чрезвычайно академических проблем, связанных с временными метками Unix, в основном связанных с генерацией временных меток. Это даже меньше заботит разрешение в миллисекундах. Как было упомянуто в другом комментарии, большинство компьютерных дат внутренне представлены как метки времени Unix, даже если они выставлены и отформатированы иначе. Тем не менее, нет ничего плохого в миллисекундном представлении любой данной даты + времени, особенно по сравнению с другими подходами, на которые легко могут повлиять те же предостережения о нано-воздействии под капотом.
Ciabaros

Просто добавьте, что касается дат «вне диапазона» для меток времени Unix: это проблемы с системным хранилищем, которые должны решаться в более широком контексте, чем транспортный формат. Например, этот формат не должен быть ограничен целыми числами, которые вписываются в 32-битные, и не должен быть строго положительными числами, но никто не собирается решать «проблему 2038 года», отбрасывая временные метки на уровне системы / архитектуры ; они просто должны быть расширены (например, до 64-разрядной или более поздней версии), и это не влияет на этот предложенный транспортный формат.
Ciabaros

3

Сам JSON не имеет формата даты, ему все равно, как кто-то хранит даты. Однако, поскольку этот вопрос помечен javascript, я предполагаю, что вы хотите знать, как хранить даты javascript в JSON. Вы можете просто передать дату JSON.stringifyметоду, и он будет использовать Date.prototype.toJSONпо умолчанию, который в свою очередь использует Date.prototype.toISOString( MDN на Date.toJSON ):

const json = JSON.stringify(new Date());
const parsed = JSON.parse(json); //2015-10-26T07:46:36.611Z
const date = new Date(parsed); // Back to date object

Я также нашел полезным использовать reviverпараметр JSON.parse( MDN в JSON.parse ) для автоматического преобразования строк ISO обратно в даты javascript всякий раз, когда я читаю строки JSON.

const isoDatePattern = new RegExp(/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/);

const obj = {
 a: 'foo',
 b: new Date(1500000000000) // Fri Jul 14 2017, etc...
}
const json = JSON.stringify(obj);

// Convert back, use reviver function:
const parsed = JSON.parse(json, (key, value) => {
    if (typeof value === 'string' &&  value.match(isoDatePattern)){
        return new Date(value); // isostring, so cast to js date
    }
    return value; // leave any other value as-is
});
console.log(parsed.b); // // Fri Jul 14 2017, etc...

2

Предпочтительным способом является использование 2018-04-23T18:25:43.511Z...

На рисунке ниже показано, почему это предпочтительный способ:

JSON Date

Итак, как вы видите, у Date есть собственный метод toJSON, который returnв этом формате и может быть легко преобразован в Date...


2
Правильный! Синтаксис обмена данными JSON не определяет стандарт: ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf, но на практике форматы, совместимые с ISO 8601, более желательны для разных платформ, включая среду выполнения JavaScript.
Камьяр Назери

1

В Sharepoint 2013 при получении данных в формате JSON отсутствует формат для преобразования даты в формат «только дата», потому что в этой дате должен быть формат ISO

yourDate.substring(0,10)

Это может быть полезно для вас


0

"2014-01-01T23: 28: 56.782Z"

Дата представлена ​​в стандартном и сортируемом формате, который представляет время UTC (обозначено Z). ISO 8601 также поддерживает часовые пояса, заменив Z на значение + или - для смещения часового пояса:

"2014-02-01T09: 28: 56.321-10: 00"

Существуют и другие варианты кодирования часового пояса в спецификации ISO 8601, но формат –10: 00 является единственным форматом TZ, который поддерживают текущие анализаторы JSON. В общем, лучше использовать формат на основе UTC (Z), если у вас нет особой необходимости выяснять часовой пояс, в котором была создана дата (возможно только при генерации на стороне сервера).

NB: переменная дата = новая дата (); console.log (дата); // Ср Янв 2014 2014 13:28:56 GMT- 1000 (Гавайское стандартное время)

var json = JSON.stringify(date);
console.log(json);  // "2014-01-01T23:28:56.782Z"

чтобы сказать вам, что это предпочтительный способ, хотя JavaScript не имеет стандартного формата для него

// JSON encoded date
var json = "\"2014-01-01T23:28:56.782Z\"";

var dateStr = JSON.parse(json);  
console.log(dateStr); // 2014-01-01T23:28:56.782Z

0

Если вы используете Kotlin, то это решит вашу проблему. (Формат MS Json)

val dataString = "/Date(1586583441106)/"
val date = Date(Long.parseLong(dataString.substring(6, dataString.length - 2)))

-3

это работа для меня с сервером разбора

{
    "ContractID": "203-17-DC0101-00003-10011",
    "Supplier":"Sample Co., Ltd",
    "Value":12345.80,
    "Curency":"USD",
    "StartDate": {
                "__type": "Date",
                "iso": "2017-08-22T06:11:00.000Z"
            }
}

-6

Существует только один правильный ответ, и большинство систем ошибаются. Количество миллисекунд с начала эпохи, 64-разрядное целое число. Часовой пояс является проблемой пользовательского интерфейса и не имеет никакого отношения к уровню приложений или уровню базы данных. Почему ваша БД заботится о том, что такое часовой пояс, когда вы знаете, что он будет хранить его как 64-битное целое число, а затем выполните вычисления преобразования.

Удалите посторонние биты и просто обрабатывайте даты как числа до пользовательского интерфейса. Вы можете использовать простые арифметические операторы для выполнения запросов и логики.


Комментарии были перемещены в чат .
Джон Клементс

5
Теперь у вас есть 2 проблемы: какую эпоху выбрать и какие миллисекунды считать? Вероятно, наиболее распространенным выбором является время Unix (1970-01-01T00: 00: 00 UTC и миллисекунды SI, за исключением тех, которые находятся в пределах високосной секунды), но, конечно, это делает будущие времена неопределенными.
МОС

2
Итак, как вы представляете микросекунды? RFC3339 отлично работает с любой точностью, у вас есть считыватель, который анализирует часовой пояс и дает вам правильную отметку времени, а также дополнительную информацию. Приложения календаря обычно заботятся о часовых поясах.
gnasher729

11
Часовой пояс не касается пользовательского интерфейса, если вы не против пропустить следующий рейс. Полеты отправляются по местному времени и следуют определенным правилам для изменений летнего времени. Потеря смещения означает потерю важной деловой информации
Panagiotis Kanavos

1
Некоторые дополнительные контраргументы включают в себя способность представлять время до 1970 года (при условии, что эта конкретная эпоха), и тенденция JSON быть несколько читабельным для человека.
Тимо

-8

Следующий код сработал для меня. Этот код будет печатать дату в формате ДД-ММ-ГГГГ .

DateValue=DateValue.substring(6,8)+"-"+DateValue.substring(4,6)+"-"+DateValue.substring(0,4);

иначе вы также можете использовать:

DateValue=DateValue.substring(0,4)+"-"+DateValue.substring(4,6)+"-"+DateValue.substring(6,8);

-19

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

{
"person" :
      {
 "name" : {
   "first": "Tom",
   "middle": "M",
  ...
}
 "dob" :  {
         "year": 2012,
         "month": 4,
         "day": 23,
         "hour": 18,
         "minute": 25,
         "second": 43,
         "timeZone": "America/New_York"
    }   
   }
}

Следует признать, что это более многословно, чем RFC 3339, но:

  • это также читабельно для человека
  • он реализует правильную объектную модель (как в ООП, насколько это позволяет JSON)
  • он поддерживает часовые пояса (не только смещение UTC на заданную дату и время)
  • он может поддерживать меньшие единицы, такие как миллисекунды, наносекунды, ... или просто доли секунды
  • он не требует отдельного шага разбора (для разбора строки даты и времени), JSON-анализатор все сделает за вас
  • простое создание с любой структурой даты и времени или реализация на любом языке
  • может быть легко расширен для поддержки других календарных шкал (иврит, китайский, исламский ...) и эпох (AD, BC, ...)
  • это год 10000 безопасно ;-) (RFC 3339 нет)
  • поддерживает даты за весь день и плавающее время (Javascript's Date.toJSON()нет)

Я не думаю, что правильная сортировка (как отмечает funroll для RFC 3339) - это функция, которая действительно необходима при сериализации даты в JSON. Также это верно только для даты и времени, имеющих одинаковое смещение часового пояса.


7
Я сомневаюсь, что кто-то будет использовать json в 10000 году, или даже в то время, когда к 10000 году все еще будет год 10000. Но если к тому времени обе эти вещи все еще верны, формат можно просто расширить, чтобы он содержал 3 цифры. век компонент. Поэтому я бы сказал, что люди могут спокойно придерживаться RFC 3339, по крайней мере, до 9900 года
память о сне

8
@ downvoters: Согласно Почему так важно голосование? Вы должны понизить, если post contains wrong information, is poorly researched, or fails to communicate information. Пожалуйста, объясните, по какой из этих причин вы отклонили этот ответ.
Мартен

5
@ Мартен Две вещи. 1. Вы никогда не должны объяснять отрицательные голоса, хотя я понимаю, что это может быть полезно. 2. Я не понизил ваш ответ, но думаю, что людям не нравится ваш ответ, потому что они думают, что это неправильный способ сделать это. Это можно было бы квалифицировать как «неправильную информацию», поскольку вопрос состоит в том, чтобы найти лучший способ что-то сделать
Кевин Уэллс

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

2
@Phil, UTC на самом деле не является часовым поясом (нет места на земле, где в качестве официального часового пояса используется «UTC»), это стандарт времени . Также смещения часового пояса довольно непредсказуемы. Невозможно сказать, если в 2025 году «12:00 по московскому времени» все еще будет «9:00 UTC», как сегодня, оно менялось несколько раз за последние 30 лет . Если вы хотите указать будущее местное время, вам нужны настоящие часовые пояса.
Мартен
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.