Como analisar JSON para receber um objeto Date em JavaScript?

117

Eu tenho um seguinte pedaço de JSON:

\/Date(1293034567877)\/

que é o resultado deste código .NET:

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

Agora, o problema que estou enfrentando é como criar um objeto Date a partir disso em JavaScript. Tudo o que consegui encontrar foi uma solução incrível de regex (muitos contendo bugs).

É difícil acreditar que não existe uma solução elegante, pois tudo isso está em JavaScrip, quero dizer, o código JavaScript tentando ler JSON (JavaScript Object Notation) que deveria ser um código JavaScript e, neste momento, não é porque o JavaScript não pode faça um bom trabalho aqui.

Também vi algumas soluções de avaliação que não consegui fazer funcionar (além de serem apontadas como ameaças à segurança).

Não há realmente nenhuma maneira de fazer isso de forma elegante?

Pergunta semelhante sem resposta real:
Como analisar o formato de data JSON ASP.NET com GWT

Piotr Owsiak
fonte
2
Você pode simplesmente passar o carimbo de data / hora para o cliente e chamá new Date()-lo.
jAndy
Se eu tivesse o carimbo de data / hora, poderia, mas tenho JSON que o JavaScript aparentemente não entende [sic!]
Piotr Owsiak

Respostas:

51

Não há representação JSON padrão de datas. Você deve fazer o que @jAndy sugeriu e não serializar um DateTime; basta enviar uma string de data RFC 1123 ToString("r")ou um número de época do Unix de segundos, ou qualquer outra coisa que você possa usar no JavaScript para construir um Date.

Jacob
fonte
3
Obrigado, eu estava indo por um caminho morto, você foi o primeiro a apontar que JSON não suporta o tipo de data.
Piotr Owsiak
3
JSON oferece suporte a números, strings, objetos, matrizes e os literais true, false e null. Uma vez que Date não é nada disso, é um tipo complexo que deve ser armazenado como um objeto, em vez de uma string, então você pode incluir informações de tipo, como o nome do tipo em membros especiais como "$ type" que nunca resolveria para um membro do objeto real. Esses meta-membros podem ser usados ​​para reviver o objeto JSON para um objeto de tempo de execução fortemente tipado posteriormente. Acho que a prática de colocar uma data em uma string é estúpida, porque cria desnecessariamente padrões de string reservados e tenta combiná-los em cada string.
Triynko
4
Agora existe um formato de data JSON padrão. tools.ietf.org/html/rfc7493#section-4.3
Bryan Larsen
128

A JSON.parsefunção aceita uma função de reviver DateTime opcional. Você pode usar uma função como esta:

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

Então ligue

JSON.parse(somejsonstring, dateTimeReviver);

E suas datas vão sair certas.

Tim
fonte
1
Bem localizado, bastante útil.
noup
5
Esta prática de codificação de dados digitados não primitivos em um tipo primitivo (string) é insana. Codifique datas em um objeto JSON com propriedades significativas ou, para ir ainda mais longe, inclua uma propriedade "$ type" no objeto JSON para que a rotina de análise / desserialização possa reviver o tipo apropriadamente e até mesmo usar conversores personalizados se você quiser empacotar todos as informações em um único valor de propriedade como "ticks" ou "ms_since_epoch".
Triynko
7
Tive que modificar o regex como este / \ / Date ((-? \ D *)) \ // para que ele pudesse lidar com números negativos também. Números negativos aparecem quando você tem um DateTime muito antigo (antes da época) que foi convertido pelo .NET para JSON.
ClearCloud8
@ ClearCloud8: Você perdeu as barras invertidas: / \ / Date \ ((-? \ D *) \) \ //
Jerther
1
Nunca soube desta função - é tão útil!
keldar
50

Esta resposta de Roy Tinker aqui :

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

Como ele diz: A função substr tira a parte "/ Date (", e a função parseInt obtém o inteiro e ignora ") /" no final. O número resultante é passado para o construtor Date.

Outra opção é simplesmente formatar suas informações corretamente no lado do ASP, de modo que o JavaScript possa lê-las facilmente. Considere fazer isso para suas datas:

DateTime.Now()

Que deve retornar um formato como este:

7/22/2008 12:11:04 PM

Se você passar isso para um Dateconstrutor JavaScript como este:

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

A variável dateagora contém este valor:

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

Naturalmente, você pode formatar esse DateTimeobjeto em qualquer tipo de string / int que o Dateconstrutor JS aceite.

face de árvore
fonte
Obrigado treeface, esta resposta me ajudou com algo recentemente!
Malice
4
Nunca, jamais, conte com os formatos de conversão de string de data <-> padrão. Usar milissegundos desde a Epoch, que permanece no domínio dos tipos numéricos, é muito mais simples e confiável.
Johan Boulé
2
Essa resposta apresenta duas soluções - a primeira é correta (o parseInt) e a segunda está errada, portanto, não tenho certeza se deve votar a favor ou contra! O problema de simplesmente imprimir como uma string é que a data pode facilmente retroceder se o servidor estiver em um país, por exemplo, EUA e o navegador em outro, por exemplo, Reino Unido.
mike nelson
A primeira resposta a me dar qualquer tipo de pista
Nick.McDermaid,
Uma resposta OK até " Considere fazer isso para seus encontros ... ". Sugerir um formato não padrão que introduza análise dependente da implementação e problemas de fuso horário não é uma boa ideia. O formato OP é preferível (embora não seja o ideal).
RobG
21

se você usar o estilo de data ISO8601 do JavaScript em JSON, você pode usar isso, do MDN

var jsonDate = (new Date()).toJSON();
var backToDate = new Date(jsonDate);
console.log(jsonDate); //2015-10-26T07:46:36.611Z
LeeGee
fonte
2
imo esta é a resposta mais elegante e deve ser a mais aceita.
John
1
Muito elegante, de fato, mas isso não se relaciona ao formato de data específico que foi mencionado na pergunta.
asiop
@aslop - se o usuário não conseguir converter uma data de / para ISO, JSON é o menor dos problemas.
LeeGee
7

Você pode converter a data JSON para o formato de data normal em JavaScript.

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

O que há de errado com:

new Date(1293034567877);

Isso retorna para mim "Quarta, 22 de dezembro de 2010 16:16:07 GMT + 0000 (hora padrão GMT)".

Ou você precisa obter o número do json?

Psytronic
fonte
3
O que há de errado com sua solução? Bem, o 1293034567877 não é o JSON que tenho, certo? Além disso, não preciso retirar o número do JSON, preciso retirar a data do JSON. Estou esperando um pouco mais do JavaScript do que apenas ser capaz de fazer tudo com regex. Preciso que meu código seja legível e não pareça uma maldição de desenho animado.
Piotr Owsiak
7
Eu culpo o .NET por produzir uma serialização de um objeto de data em um formato tão estranho quanto \/Date(1293034567877)\/. Se fosse normal, ele apenas geraria o tempo de época e você poderia inicializar um objeto Date com isso.
Quentin
2
@treeface: Se JSON não é JavaScript, então acho que tutoriais e livros são os culpados por esse equívoco comum. De qualquer forma, fico feliz em ser corrigido, na verdade. Quanto à sua sugestão de que Date pode ser representado como String, posso dizer que tudo pode ser representado como String, certo? Mas isso não tornaria nosso trabalho mais fácil, mas terrivelmente doloroso e infernal. Acho que meu problema decorre do fato de que considerei JSON como um formato de serialização (anunciado para ocupar menos largura de banda e funcionar melhor com JavaScript do que XML). Acontece que não é, pelo menos não indolor.
Piotr Owsiak de
1
@treeface: Pesquisei no Google sua afirmação sobre JSON e descobri que JSON é JavaScript, na verdade, é um subconjunto de JavaScript. Consulte RFC # 4627 "O tipo de mídia application / json para JavaScript Object Notation (JSON)" e procure uma declaração: "Os objetivos de design do JSON eram que ele fosse mínimo, portátil, textual e um subconjunto de JavaScript.". Agora, quando penso sobre isso, parece óbvio, pois você pode chamar eval () em JSON.
Piotr Owsiak de
1
@David Dorward: Eu preferiria que a complexidade adicionada fosse implementada em bibliotecas (seja .NET, Java, Ruby, Python ou qualquer linguagem / plataforma em que você esteja) em vez de deixar os detalhes para serem tratados pelo programador. Observe também que você não precisa de suporte a tipos de dados booleanos e inteiros em JSON, você pode apenas colocá-los em strings, certo? Você pode imaginar como seria horrível obter algo do JSON então?
Piotr Owsiak de
2

Eu sei que este é um tópico muito antigo, mas gostaria de postar isso para ajudar aqueles que esbarraram nisso como eu fiz.

se você não se importa em usar um script de terceiros, pode usar moment, js. Então, você pode usar .format () para formatá-lo para qualquer coisa que desejar.

Eman
fonte
2

As datas são sempre um pesadelo. Respondendo à sua velha pergunta, talvez esta seja a maneira mais elegante:

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

Com eval, convertemos nossa string em código javascript. Em seguida, removemos o "/", para a função de substituição é uma expressão regular. À medida que começamos com novo, então nossas frases irão executar isto:

new Date(1455418800000)

Agora, uma coisa que comecei a usar há muito tempo, são valores longos representados em ticks ... por quê? bem, localização e pare de pensar em como a data é configurada em cada servidor ou cada cliente. Na verdade, eu também o uso em bancos de dados.

Talvez seja muito tarde para esta resposta, mas pode ajudar qualquer um aqui.

Gabriel Andrés Brancolini
fonte
A propósito, meu inglês com os anos está piorando do que nunca ... mas acho que me fiz entender.
Gabriel Andrés Brancolini
Sua resposta funciona muito bem, me ajudou a sair de um engarrafamento. Obrigado.
BoredBsee
1

O AngularJS também não conseguiu analisar a /Date(xxxxxxxxxxxxx)/string de data JSON .NET .

Eu resolvi esse problema formatando a data para sua representação de string ISO 8601 em vez de despejar o Dateobjeto diretamente ...

Aqui está um exemplo de código ASP.NET MVC.

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

Tentei, RFC 1123mas não funcionou. O Angular trata isso como string em vez de Data.

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

Eu não usei .Net para coisas assim. Se você conseguiu imprimir algo como o seguinte, ele deve funcionar.

Observe, a menos que você esteja analisando essa string JSON por algum outro meio ou apenas espere que os usuários tenham navegadores modernos com um analisador JSON integrado, você precisa usar uma estrutura JS ou JSON2 para analisar a string JSON gerada pelo servidor em um JSON real objeto.

// 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

Navegadores modernos, como Firefox 3.5 e Internet Explorer 8, incluem recursos especiais para analisar JSON. Como o suporte nativo do navegador é mais eficiente e seguro do que eval (), espera-se que o suporte nativo JSON seja incluído no próximo padrão ECMAScript. [6]


Link para arquivo JSON2

Exemplo ao Vivo

subhaze
fonte
Eu entendi, mas meu problema com JSON e tipo de data é que eu preciso fazer explicitamente "nova data (" que é a) trabalho extra b) conhecimento adicional que precisa ser comunicado ao consumidor. Estou muito desapontado ao descobrir como isso é tratado e, basicamente, considero um erro na especificação JSON.
Piotr Owsiak
0

A resposta a esta pergunta é: use o nuget para obter JSON.NET e, em seguida, use isto dentro do seu JsonResultmétodo:

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

dentro da sua visualização, faça isso em javascript:

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

Se for uma chamada 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); });

Depois de JSON.parseser chamado, você pode colocar a data JSON em uma new Dateinstância porque JsonConvertcria uma instância de hora ISO adequada

Callum Linington
fonte
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;
};
Muzafar
fonte
0

Como Callum mencionou, para mim, a melhor maneira é mudar o método Controller para string em vez de JsonResult ".

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

A partir do método ajax, você pode fazer algo assim

 $.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
fonte
0

usando a função eval funciona apenas tem que remover a barra na frente e atrás.

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

rende Qui, 01 de janeiro de 1970 00:00:00 GMT-0700 (Horário Padrão das Montanhas dos EUA)

vernmico
fonte
0

Eu tive um problema com a API externa fornecendo datas neste formato, algumas vezes até com informações de diferença UTC como /Date(123232313131+1000)/. Consegui transformá-lo em um Dateobjeto js com o seguinte código

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);
  }
}
Martin Vich
fonte
-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(); 
}
Sunil
fonte
2
Você não está retornando um objeto de data, pelo que eu entendo o código.
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;
};

// Use esta função

var objDate=parseJsonDate("\/Date(1443812400000)\/");
alert(objDate);
Muzafar Hasan
fonte