Як розібрати JSON для отримання об’єкта Date в JavaScript?


117

У мене є такий фрагмент JSON:

\/Date(1293034567877)\/

що є результатом цього коду .NET:

var obj = DateTime.Now;
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
serializer.Serialize(obj).Dump();

Тепер проблема, з якою я стикаюся, полягає в тому, як створити з цього об’єкта Date в JavaScript. Все, що я міг знайти, - це неймовірне рішення для регулярного генерування (багато містять помилок).

Важко повірити, що немає елегантного рішення, оскільки це все в JavaScrip, я маю на увазі код JavaScript, який намагається прочитати JSON (JavaScript Object Notation), який повинен бути кодом JavaScript, і в цей момент виявляється, що це не викликає JavaScript зробіть тут хорошу роботу.

Я також бачив деякі рішення eval, які я не міг змусити працювати (крім того, що вони зазначили як загрозу безпеці).

Невже насправді немає елегантного способу зробити це?

Аналогічне запитання без реальної відповіді:
Як проаналізувати формат дати ASP.NET JSON з GWT


2
Ви можете просто передати мітку часу клієнту і зателефонувати new Date()за ним.
jAndy

Якби у мене була мітка часу, я міг би, але у мене є JSON, який JavaScript, мабуть, не розуміє [sic!]
Piotr Owsiak

Відповіді:


51

Не існує стандартного представлення дати JSON. Ви повинні робити те, що запропонував @jAndy, і зовсім не серіалізувати DateTime; просто надішліть рядок дати RFC 1123 ToString("r")або секунду від Unix-епохи, або щось інше, що ви можете використовувати в JavaScript для створення Date.


3
Дякую, що я йшов мертвим шляхом, ви першим зазначили, що JSON не підтримує тип дати.
Piotr Owsiak

3
JSON підтримує числа, рядки, об'єкти, масиви та літерали true, false та null. Оскільки Date не є одним із таких, це складний тип, який повинен зберігатися як об'єкт, а не як рядок, тому ви можете включати інформацію про тип, наприклад, ім'я типу, у спеціальні члени типу "$ type", які ніколи не вирішуватимуть реальний член об'єкта. Такі мета-члени можна використовувати для відновлення об'єкта JSON до сильно типізованого об'єкта виконання пізніше. Я думаю, що практика вставки дати в рядку є дурною, тому що вона надмірно створює зарезервовані рядкові шаблони і намагається зіставити їх у кожному рядку.
Трайнко

4
Зараз існує стандартний формат дати JSON. tools.ietf.org/html/rfc7493#section-4.3
Брайан Ларсен

128

JSON.parseФункція приймає додаткову функцію DateTime Reviver. Ви можете використовувати таку функцію:

dateTimeReviver = function (key, value) {
    var a;
    if (typeof value === 'string') {
        a = /\/Date\((\d*)\)\//.exec(value);
        if (a) {
            return new Date(+a[1]);
        }
    }
    return value;
}

Тоді дзвоніть

JSON.parse(somejsonstring, dateTimeReviver);

І ваші побачення вийдуть правильно.


1
Добре помічений, досить корисний.
noup

5
Ця практика кодування непомітивних типізованих даних у примітивний тип (рядок) є божевільною. Кодуйте дати в об’єкті JSON зі значущими властивостями або для того, щоб піти ще далі, включіть у об’єкт JSON властивість "$ type", щоб рутина розбору / деріаріалізації могла відповідним чином відновити тип і навіть використовувати спеціальні перетворювачі, якщо ви хочете спакувати всі інформація в єдине значення властивості, наприклад "тички" або "ms_since_epoch".
Трайнко

7
Мені довелося змінити регулярний вираз, як цей / \ / Дата ((-? \ D *)) \ //, щоб він також міг обробляти негативні числа. Негативні номери з'являються, коли у вас є дуже старий DateTime (до епохи), який був перетворений .NET в JSON.
ClearCloud8

@ ClearCloud8: Ви пропускаєте зворотні косої риси: / \ / Дата \ ((-? \ D *) \) \ //
Jerther

1
Я ніколи не знав про цю функцію - це так корисно!
keldar

50

Відповідь Роя Тінкера тут :

var date = new Date(parseInt(jsonDate.substr(6)));

Як він каже: Функція substr виймає частину "/ Date (", а функція parseInt отримує ціле число і в кінці ігнорує ") /". Отримане число передається в конструктор Date.

Інший варіант - просто форматувати свою інформацію належним чином на стороні ASP, щоб JavaScript міг її легко читати. Подумайте про це для своїх побачень:

DateTime.Now()

Який повинен повернути такий формат:

7/22/2008 12:11:04 PM

Якщо ви передаєте це в Dateконструктор JavaScript так:

var date = new Date('7/22/2008 12:11:04 PM');

Тепер змінна dateмістить це значення:

Tue Jul 22 2008 12:11:04 GMT-0700 (Pacific Daylight Time)

Звичайно, ви можете відформатувати цей DateTimeоб'єкт у будь-який тип рядка / int, який Dateприймає конструктор JS .


Спасибі дерево, ця відповідь допомогла мені щось із нещодавно!
Malice

4
Ніколи і ніколи не покладайтеся на формати конвертації рядків <-> за замовчуванням. Використовувати мілісекунди з моменту Epoch, який залишається в домені числових типів, набагато простіше і надійніше.
Йоган Буле

2
У цій відповіді представлено два рішення - перше - правильне (аналіз parseInt), а друге - неправильне, тож не впевнене, чи потрібно відхиляти чи знижувати! Проблема простого виведення в якості рядка полягає в тому, що дата може легко повернутись назад, якщо сервер знаходиться в одній країні, наприклад, США та веб-переглядачі, наприклад, Великобританії.
Майк Нельсон

Перша відповідь, щоб дати мені будь-яку підказку
Nick.McDermaid

Відповідь ОК, поки " Подумайте про це для своїх побачень ... ". Запропонувати нестандартний формат, який запроваджує розбір залежних від впровадження проблем та часових поясів, не є хорошою ідеєю. Формат ОП є кращим (хоча і не ідеальним).
RobG

21

якщо ви використовуєте дату стилю JavaScript ISO8601 в JSON, ви можете використовувати це від MDN

var jsonDate = (new Date()).toJSON();
var backToDate = new Date(jsonDate);
console.log(jsonDate); //2015-10-26T07:46:36.611Z

2
imo це найелегантніша відповідь і повинна бути прийнятою.
Джон

1
Дійсно дуже елегантно, але це не стосується конкретного формату дати, про який згадувалося в питанні.
asiop

@aslop - якщо користувач не може перетворити дату в / з ISO, тоді JSON - найменша проблема.
LeeGee

7

Ви можете перетворити дату JSON у звичайний формат дати в JavaScript.

var date = new Date(parseInt(jsonDate.substr(6)));

6

Що не так з:

new Date(1293034567877);

Це повертається для мене "Wed Dec 22 2010 16:16:07 GMT + 0000 (GMT стандартний час)".

Або вам потрібно дістати номер json?


3
Що не так у вашому рішенні? Що ж, 1293034567877 - це не той JSON, чи не так? Крім того, мені не потрібно отримувати номер JSON, мені потрібно отримати дату JSON. Я чекаю трохи більше JavaScript, ніж просто вміти робити все з регексом. Мені потрібно, щоб мій код був читабельним і не був схожим на мультфільм прокляття.
Пьотр Осяк

7
Я б звинувачував .NET у створенні серіалізації об'єкта дати у такому дивному форматі \/Date(1293034567877)\/. Якби це було здорово, він би просто виводив час епохи, і ви можете ініціалізувати об'єкт Date з цим.
Квентін

2
@treeface: Якщо JSON не JavaScript, то я думаю, що підручники та книги повинні звинувачуватися в цьому поширеному непорозумінні. У будь-якому разі я з радістю стою виправлений, дійсно. Що стосується вашої пропозиції про те, що Date може бути представлений як String, я можу сказати, що все може бути представлено як String, правда? Але це не полегшило б нашу роботу, а жахливо болісне і пекельне. Я думаю, що моя проблема випливає з того, що я розглядав JSON як формат серіалізації (рекламується з меншою пропускною здатністю та краще працює з JavaScript, ніж XML). Як виявляється, це не принаймні не безболісно.
Piotr Owsiak

1
@treeface: Я google ваші претензії щодо JSON і з'ясував, що JSON - це JavaScript, насправді це підмножина JavaScript. Див. RFC № 4627 "Тип мультимедійного додатку / json для нотації об'єкта JavaScript (JSON)" і шукай твердження: "Цілі дизайну JSON повинні були бути мінімальними, портативними, текстовими та підмножиною JavaScript." Тепер, коли я думаю про це, здається очевидним, як можна назвати eval () на JSON.
Piotr Owsiak

1
@David Dorward: Я вважаю за краще, щоб додаткова складність була реалізована в бібліотеках (будь-які .NET, Java, Ruby, Python, або мова / платформа, на якій ви перебуваєте), а не залишала деталі для обробки програмістом. Також зауважте, що в JSON вам не потрібна підтримка булевих і цілих типів даних, ви можете просто поставити їх у рядки, правда? Ви можете собі уявити, наскільки дивним було б тоді отримати що-небудь від JSON?
Piotr Owsiak

2

Я знаю, що це дуже стара тема, але я хочу опублікувати це, щоб допомогти тим, хто натрапив на це, як я.

якщо вам не важливо використовувати сторонній скрипт, ви можете використовувати момент, js Тоді ви можете використовувати .format (), щоб відформатувати його до всього, що вам потрібно.


2

Фініки - це завжди кошмар. Відповідаючи на старе запитання, можливо, це найелегантніший спосіб:

eval(("new " + "/Date(1455418800000)/").replace(/\//g,""))

З eval ми перетворюємо наш рядок у код JavaScript. Потім ми видаляємо "/", у функції заміни - це регулярний вираз. Починаючи з нового, тоді наші речення виправдовують це:

new Date(1455418800000)

Тепер одне, що я почав використовувати давно, - це довгі значення, які представлені в кліщах ... чому? ну, локалізація та перестаньте думати, як налаштована дата на кожному сервері чи кожному клієнті. Насправді я його також використовую в базах даних.

Можливо, для цієї відповіді досить пізно, але хтось тут може допомогти.


До речі, моя англійська з роками стає гіршою, ніж будь-коли ... але я здогадуюсь, я зрозумів себе.
Габріель Андрес Бранколіні

Ваша відповідь чудово працює, допомогла мені вийти з варення. Дякую.
BoredBsee

1

AngularJS також не міг розібрати /Date(xxxxxxxxxxxxx)/рядок дати .NET JSON ..

Я зі сторони вирішив цю проблему, відформатувавши дату в її рядковій репрезентації ISO 8601 замість того, щоб Dateбезпосередньо скидати об'єкт ...

Ось зразок коду MVC ASP.NET ..

return Json(new { 
  date : DateTime.Now.ToString("O") //ISO 8601 Angular understands this format
});

Я спробував, RFC 1123але це не працює. Кутовий трактує це як рядок замість дати.

return Json(new { 
  date : DateTime.Now.ToString("R") //RFC 1123 Angular won't parse this
});

0

Я не використовував. Net для таких речей. Якщо вам вдалося змусити його надрукувати щось на зразок наступного, це повинно працювати.

Зауважте, якщо ви не аналізуєте цю рядок JSON якимись іншими способами або не очікуєте, що користувачі мають сучасні броузери зі вбудованим аналізатором JSON, вам потрібно використовувати рамку JS або JSON2, щоб проаналізувати рядок JSON, виведений сервером, на справжній JSON об’єкт.

// JSON received from server is in string format
var jsonString = '{"date":1251877601000}';

//use JSON2 or some JS library to parse the string
var jsonObject =  JSON.parse( jsonString );

//now you have your date!
alert( new Date(jsonObject.date) );

Wiki Link

Сучасні браузери, такі як Firefox 3.5 та Internet Explorer 8, містять спеціальні функції для розбору JSON. Оскільки підтримка нативного браузера є більш ефективною та безпечною, ніж eval (), очікується, що підтримка нативної JSON буде включена до наступного стандарту ECMAScript. [6]


Посилання на файл JSON2

Живий приклад


Я розумію, але моя проблема з JSON та типом Date полягає в тому, що мені потрібно явно виконати "нову дату" (яка є) додатковою роботою; b) додаткову інформацію, яку потрібно повідомити споживачеві. Я дуже розчарований, дізнавшись, як це вирішується, і я в основному вважаю це помилкою в специфікації JSON.
Пьотр Овсяк

0

Відповідь на це запитання полягає у використанні nuget, щоб отримати JSON.NET, а потім використовувати це всередині вашого JsonResultметоду:

JsonConvert.SerializeObject(/* JSON OBJECT TO SEND TO VIEW */);

всередині вашого зору просто зробити це javascript:

JSON.parse(/* Converted JSON object */)

Якщо це дзвінок в Ajax:

var request = $.ajax({ url: "@Url.Action("SomeAjaxAction", "SomeController")", dataType: "json"});
request.done(function (data, result) { var safe = JSON.parse(data); var date = new Date(safe.date); });

Після JSON.parseвиклику ви можете ввести дату JSON в new Dateекземпляр, оскільки JsonConvertстворюється належний екземпляр часу ISO


0
function parseJsonDate(jsonDate) {

    var fullDate = new Date(parseInt(jsonDate.substr(6)));
    var twoDigitMonth = (fullDate.getMonth() + 1) + ""; if (twoDigitMonth.length == 1) twoDigitMonth = "0" + twoDigitMonth;

    var twoDigitDate = fullDate.getDate() + ""; if (twoDigitDate.length == 1) twoDigitDate = "0" + twoDigitDate;
    var currentDate = twoDigitMonth + "/" + twoDigitDate + "/" + fullDate.getFullYear();

    return currentDate;
};

0

Як згадував Callum, для мене найкращим способом є зміна методу Controller на string замість JsonResult ".

public string GetValues()
{
  MyObject.DateFrom = DateTime.Now;
  return JsonConvert.SerializeObject(MyObject);
}

З методу ajax можна зробити щось подібне

 $.ajax({
 url: "/MyController/GetValues",
 type: "post",
 success: function (data) {
 var validData = JSON.parse(data);
//if you are using datepicker and you want set a format
$("#DateFrom").val($.datepicker.formatDate("dd/mm/yy", new Date(validData.DateFrom)));                                      
// if you want the date as returned
$("#DateFrom").val(new Date(validData.DateFrom))
}
});

0

Використовуючи функцію eval, потрібно просто зняти нахил вперед і ззаду.

var date1 = "/Date(25200000)/"
eval("new " + date1.substring(1, date1.length - 1));

врожайність Чт 1 січня 1970 00:00:00 GMT-0700 (американський гірський стандартний час)


0

Я зіткнувся з проблемою із зовнішнім API, що надає дати в такому форматі, іноді навіть з інформацією про різницю в UTC /Date(123232313131+1000)/. Я зміг перетворити його на js Dateоб’єкт із наступним кодом

var val = '/Date(123232311-1000)/';
var pattern = /^\/Date\([0-9]+((\+|\-)[0-9]+)?\)\/$/;
var date = null;

// Check that the value matches /Date(123232311-1000)/ format
if (pattern.test(val)) {
  var number = val.replace('/Date(', '',).replace(')/', '');
  if (number.indexOf('+') >= 0) {
    var split = number.split('+');
    number = parseInt(split[0]) + parseInt(split[1]);
  } else if (number.indexOf('-') >= 0) {
    var split = number.split('-');
    number = parseInt(split[0]) - parseInt(split[1]);
  } else {
    number = parseInt(number);
    date = new Date(number);
  }
}

-1
//
// formats a .net date into a javascript compatible date
//
function FormatJsonDate(jsonDt) 
{              
    var MIN_DATE = -62135578800000; // const

    var date = new Date(parseInt(jsonDt.substr(6, jsonDt.length-8)));                                                       
    return date.toString() == new Date(MIN_DATE).toString() ? "" : (date.getMonth() + 1) + "\\" + date.getDate() + "\\" + date.getFullYear(); 
}

2
Ви не повертаєте об'єкт дати, наскільки я розумію код.
Йохан Буле

-1
function parseJsonDate(jsonDate) {

    var fullDate = new Date(parseInt(jsonDate.substr(6)));
    var twoDigitMonth = (fullDate.getMonth() + 1) + ""; if (twoDigitMonth.length == 1) twoDigitMonth = "0" + twoDigitMonth;

    var twoDigitDate = fullDate.getDate() + ""; if (twoDigitDate.length == 1) twoDigitDate = "0" + twoDigitDate;
    var currentDate = twoDigitMonth + "/" + twoDigitDate + "/" + fullDate.getFullYear();

    return currentDate;
};

// Використовуйте цю функцію

var objDate=parseJsonDate("\/Date(1443812400000)\/");
alert(objDate);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.