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


1137

Я бачив так багато різних стандартів для формату дати 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
Однак вбудований в JavaScript об'єкт JSON та ISO8601 містить всю інформацію, яку слід зрозуміти людині та комп'ютеру, і не покладається на початок епохи комп'ютера (1970-1-1).
poussma

Відповіді:


1847

Сам JSON не визначає, як дати мають бути представлені, але JavaScript робить.

Ви повинні використовувати формат, випромінюваний методом Date' 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 березня. Це залежить від того, використовується американський або інший формат.
Juanal

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

54
Щодо другого пункту, він не сортується правильно після 10000 року. Однак у нас майже 8000 років, щоб придумати новий формат, тому, мабуть, це не проблема.
Ерфа

7
Насправді, @Erfa, оскільки -з'явиться перед цифрами ASCII, вона буде сортувати лише до 100 000 року. ; P
Ben Leggiero

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/… ). Найкраща практика - дотримуватися однієї (розумної) конвенції, що б там не було. Як я зазначив у відповіді, найкращим способом вирішення цього питання є визначення функції утиліти для розбору дати, яка може обробляти очікувані формати. Якщо ви інтегруєтесь із системами, що використовують різні формати, функція повинна обробляти кожен випадок.
Russ Cam

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

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

3
@ gnasher729 у вас є посилання?
Russ Cam

@vallismortis - Це проект специфікації для визначення схеми для даної структури json, обмінюється між сторонами, а не формат дат у специфікації json. Я буду переглядати свою відповідь, грунтуючись на коментарях, не здається, я зрозумів достатньо
Russ Cam

27

Від RFC 7493 (Формат повідомлення I-JSON) :

I-JSON означає або Інтернет JSON, або сумісний JSON, залежно від того, кого ви запитуєте.

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


2
Це також формат, створений Date().toISOString()і Date().toJSON(), з обмеженням, Dateякий не відстежує значення часового поясу, і, отже, завжди випромінює часові позначки в Zчасовому поясі UTC ( ). Значення можна проаналізувати за допомогою new Date("...")і Date.parseDate.
Søren Løvborg

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
Sudhanshu Mishra

@SudhanshuMishra Застереження, на які ви посилаєтесь, - це загальні проблеми, що стосуються надзвичайно академічних проблем часових міток Unix, в основному пов'язаних з генерацією часових міток. Це викликає менше занепокоєння з роздільною здатністю мілісекунд. Як зазначалося в іншому коментарі, більшість комп’ютерних дат внутрішньо представлені як часові позначки unix, навіть якщо вони викриваються та відформатовані інакше. Тим не менш, немає нічого поганого в мілісекундному представленні будь-якої дати + часу, особливо в порівнянні з іншими підходами, на які можна легко вплинути на ті самі нано-наслідкові застереження під кришкою.
Чіабарос

Просто додамо, що стосується занепокоєння "поза межами" дат для часових позначок 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

Отже, як ви бачите, Дата має власний метод 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: var date = нова дата (); console.log (дата); // Ср 01 січня 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-бітове ціле число. "Часова зона" - це проблема інтерфейсу користувача і не має жодної справи на рівні додатків або рівня "db". Чому ваш db небайдужий, що таке часовий пояс, коли ви знаєте, що він буде зберігати його як 64-бітове ціле число, тоді робіть розрахунки перетворення.

Скрепіть сторонні шматочки і просто розглядайте дати як числа до інтерфейсу користувача. Ви можете використовувати прості арифметичні оператори для запитів і логіки.



5
Зараз у вас є 2 проблеми: яку епоху вам вибрати, і які мілісекунди слід порахувати? Мабуть, найпоширеніший вибір - час Unix (1970-01-01T00: 00: 00 UTC та мілісекунди SI, за винятком тих, що потрапляють у стрибкову секунду), але, звичайно, це робить майбутні часи невизначеними.
аїй

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

11
Часовий пояс не стосується інтерфейсу користувача, якщо ви не заперечуєте пропустити наступний рейс. Рейси розміщуються за місцевим часом та дотримуються конкретних правил щодо зміни DST. Втратити компенсацію означає втрату важливої ​​ділової інформації
Панайотис Канавос

1
Деякі подальші контраргументи включають здатність представляти часи до 1970 року (якщо припустити, що конкретна епоха), і тенденція JSON бути дещо зрозумілою для людини.
Тимо

-8

Наступний код працював для мене. Цей код буде друкувати дату в DD-MM-YYYY форматі.

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, але:

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

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


7
Я сумніваюся, хтось буде використовувати json у 10000 році, або навіть, що на той час рік 10000 все ще буде роком 10000. Але якщо обидва ці речі досі залишаються вірними, формат можна просто розширити, щоб він містив 3-значну цифру століття компонент. Тому я б сказав, що люди можуть спокійно дотримуватися RFC 3339, принаймні до 9900 року
пам’ять про сон

8
@downvoters: Відповідно до Чому важливе значення має голосування? вам слід спростувати, якщо a post contains wrong information, is poorly researched, or fails to communicate information. Поясніть, будь ласка, з якої з цих причин ви спростували цю відповідь.
Мартен

5
@Marten Дві речі. 1. Вам ніколи не заборгували пояснень для молодих людей, хоча я розумію, що це може бути корисним. 2. Я не спростував вашої відповіді, але я б припустив, що людям не подобається ваша відповідь, оскільки вони думають, що це не так. Це може кваліфікувати це як "Неправильну інформацію", оскільки питання шукає найкращий спосіб зробити щось
Кевін Уеллс

7
Я вас не порушив, але, безумовно, можу зрозуміти, як "винайти ще один погано визначений формат" (який, в основному, ви говорите), буде сприйматися як неправильний або погано досліджений.
аїй

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