Как разобрать 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), который должен быть кодом JavaScript, и на данный момент оказывается, что это не значит, что JavaScript не может хорошо поработай здесь.

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

Неужели нет способа сделать это элегантно?

Аналогичный вопрос без реального ответа:
как разобрать формат даты ASP.NET JSON с помощью GWT

Петр Овсяк
источник
2
Вы можете просто передать временную метку клиенту и вызвать new Date()его.
jAndy
Если бы у меня была временная метка, я бы мог, но у меня есть JSON, который JavaScript явно не понимает [sic!]
Петр Овсяк,

Ответы:

51

Стандартного представления дат в формате JSON не существует. Вы должны делать то, что предлагает @jAndy, и вообще не сериализовать a DateTime; просто отправьте строку даты RFC 1123 ToString("r")или номер эпохи в секундах от Unix, или что-то еще, что вы можете использовать в JavaScript для создания файла Date.

Иаков
источник
3
Спасибо, я пошел по мертвому пути, вы были первым, кто указал, что JSON не поддерживает тип Date.
Петр Овсяк,
3
JSON поддерживает числа, строки, объекты, массивы и литералы true, false и null. Поскольку Date не относится к таковым, это сложный тип, который следует хранить как объект, а не строку, поэтому вы можете включить информацию о типе, такую ​​как имя типа, в специальные члены, такие как «$ type», которые никогда не будут преобразованы в член реального объекта. Такие мета-члены можно использовать для преобразования объекта JSON в объект среды выполнения со строгой типизацией позже. Я считаю, что вставлять дату в строку глупо, потому что она без надобности создает зарезервированные строковые шаблоны и пытается сопоставить их в каждой строке.
Трийнко 02
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 02 фев.13,
5
Такая практика кодирования непримитивно типизированных данных в примитивном типе (строке) безумна. Кодируйте даты в объекте JSON со значимыми свойствами или, чтобы пойти еще дальше, включите свойство «$ type» в объект JSON, чтобы процедура синтаксического анализа / десериализации могла соответствующим образом оживить тип и даже использовать настраиваемые преобразователи, если вы хотите упаковать все информацию в одно значение свойства, например, «ticks» или «ms_since_epoch».
Трийнко 02
7
Мне пришлось изменить регулярное выражение следующим образом / \ / Date ((-? \ D *)) \ //, чтобы оно могло также обрабатывать отрицательные числа. Отрицательные числа появляются, когда у вас есть очень старый DateTime (до Epoch), который был преобразован .NET в JSON.
ClearCloud8
@ ClearCloud8: Вы пропускаете обратную косую черту: / \ / Date \ ((-? \ D *) \) \ //
Джертер
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 .

treeface
источник
Спасибо treeface, этот ответ недавно помог мне в чем-то!
Malice
4
Никогда и никогда не полагайтесь на форматы преобразования строки <-> по умолчанию. Использование миллисекунд, начиная с Epoch, которая остается в области числовых типов, намного проще и надежнее.
Johan Boulé
2
В этом ответе представлены два решения - первое правильное (parseInt), а второе неправильное, поэтому не уверен, голосовать за или против! Проблема с простым выводом в виде строки состоит в том, что дату можно легко перевернуть назад, если сервер находится в одной стране, например США, а браузер - в другой, например Великобритании.
Майк Нельсон
Первый ответ, который даст мне хоть какую-то подсказку
Nick.McDermaid
Нормальный ответ, пока не « Подумайте о том, чтобы сделать это для ваших свиданий… » Предлагать нестандартный формат, который вводит проблемы синтаксического анализа в зависимости от реализации и часовых поясов, не является хорошей идеей. Формат OP предпочтительнее (хотя и не идеален).
RobG
21

если вы используете дату ISO8601 в стиле JavaScript в JSON, вы можете использовать это из MDN

var jsonDate = (new Date()).toJSON();
var backToDate = new Date(jsonDate);
console.log(jsonDate); //2015-10-26T07:46:36.611Z
LeeGee
источник
2
Имо, это самый элегантный ответ, и он должен быть принятым.
Джон
1
Действительно, очень элегантно, но это не относится к конкретному формату даты, упомянутому в вопросе.
asiop
@aslop - если пользователь не может преобразовать дату в / из ISO, то JSON - наименьшая из проблем.
LeeGee
7

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

var date = new Date(parseInt(jsonDate.substr(6)));
ViPuL5
источник
6

Что случилось с:

new Date(1293034567877);

Это возвращается для меня «среда, 22 декабря 2010 г., 16:16:07 GMT + 0000 (стандартное время по Гринвичу)».

Или вам нужно вывести номер из json?

Psytronic
источник
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: Я сделал ваше заявление о JSON в Google и выяснил, что JSON - это JavaScript, на самом деле это подмножество JavaScript. См. RFC # 4627 «Тип носителя application / json для нотации объектов JavaScript (JSON)» и найдите утверждение: «Цели дизайна JSON заключались в том, чтобы он был минимальным, переносимым, текстовым и подмножеством JavaScript». Теперь, когда я думаю об этом, это кажется очевидным, поскольку вы можете вызвать eval () в JSON.
Петр Овсяк
1
@ Дэвид Дорвард: Я бы предпочел, чтобы дополнительная сложность была реализована глубоко внутри библиотек (.NET, Java, Ruby, Python или на любом языке / платформе, на которой вы работаете), а не оставлял детали на усмотрение программиста. Также обратите внимание, что вам не нужна поддержка логических и целочисленных типов данных в JSON, вы можете просто поместить их в строки, верно? Можете ли вы представить себе, насколько ужасно было бы получить что-нибудь от JSON?
Петр Овсяк
2

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

если вам не нужен сторонний скрипт, вы можете использовать moment, js. Затем вы можете использовать .format (), чтобы отформатировать его так, как вы хотите.

Эман
источник
2

Свидания - всегда кошмар. Отвечая на ваш старый вопрос, возможно, это самый элегантный способ:

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

С помощью eval мы конвертируем нашу строку в код javascript. Затем убираем «/», в функцию замены входит регулярное выражение. Поскольку мы начинаем с нового, наши предложения будут исключать это:

new Date(1455418800000)

Одна вещь, которую я начал использовать очень давно, - это длинные значения, которые представлены в тиках ... почему? ну, локализация и перестаньте думать, как настраивается дата на каждом сервере или каждом клиенте. Фактически, я тоже использую его в базах данных.

Возможно, уже довольно поздно для этого ответа, но может помочь любому здесь.

Габриэль Андрес Бранколини
источник
Кстати, мой английский с годами становится хуже, чем когда-либо ... но я думаю, что я понял себя.
Габриэль Андрес Бранколини,
Ваш ответ отлично работает, помог мне выбраться из затора. Спасибо.
BoredBsee
1

AngularJS также не смог проанализировать /Date(xxxxxxxxxxxxx)/строку даты .NET JSON .

Я решил эту проблему, отформатировав дату в строковое представление ISO 8601 вместо того, чтобы Dateнапрямую выгружать объект ...

Вот образец кода ASP.NET MVC ..

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

Я пробовал, RFC 1123но это не сработало .. Angular рассматривает это как строку вместо даты.

return Json(new { 
  date : DateTime.Now.ToString("R") //RFC 1123 Angular won't parse this
});
Росди Касым
источник
0

Я не использовал .Net для подобных вещей. Если вам удалось заставить его напечатать что-то вроде следующего, он должен работать.

Обратите внимание, если вы не анализируете эту строку JSON каким-либо другим способом или не ожидаете, что у пользователей будут современные браузеры со встроенным анализатором JSON, вам необходимо использовать JS framework или 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) );

Вики-ссылка

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


Ссылка на файл JSON2

Живой пример

subhaze
источник
Я понимаю, но моя проблема с типом JSON и Date заключается в том, что мне нужно явно выполнить «новую дату» (которая является а) дополнительной работой б) дополнительными знаниями, которые необходимо сообщить потребителю. Я очень разочарован, узнав, как с этим справляются, и в основном считаю это ошибкой в ​​спецификации 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

Как сказал Каллум, для меня лучший способ - изменить метод контроллера на строковый вместо 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))
}
});
onixpam
источник
0

использование функции eval работает, просто нужно удалить косую черту спереди и сзади.

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

дает Thu Jan 01 1970 00:00:00 GMT-0700 (Горное стандартное время США)

vernmic
источник
0

У меня возникла проблема с внешним API, предоставляющим даты в этом формате, иногда даже с информацией о разнице в формате UTC, например /Date(123232313131+1000)/. Мне удалось превратить его в Dateобъект js с помощью следующего кода

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
Вы не возвращаете объект даты, насколько я понимаю код.
Johan Boulé,
-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);
Музафар Хасан
источник