Jak przeanalizować JSON, aby otrzymać obiekt Date w JavaScript?

117

Mam następujący fragment JSON:

\/Date(1293034567877)\/

co jest wynikiem tego kodu .NET:

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

Teraz mam problem z tym, jak utworzyć obiekt Date z tego w JavaScript. Jedyne, co mogłem znaleźć, to niesamowite rozwiązanie regex (wiele zawierało błędy).

Trudno uwierzyć, że nie ma eleganckiego rozwiązania, bo to wszystko jest w JavaScripcie, mam na myśli kod JavaScript próbujący odczytać JSON (JavaScript Object Notation), który ma być kodem JavaScript iw tym momencie okazuje się, że nie jest to spowodowane tym, że JavaScript nie może zrób dobrą robotę tutaj.

Widziałem też kilka rozwiązań ewaluacyjnych, których nie mogłem wykonać (poza tym, że zostały wskazane jako zagrożenie bezpieczeństwa).

Czy naprawdę nie da się tego zrobić w elegancki sposób?

Podobne pytanie bez prawdziwej odpowiedzi:
jak analizować format daty ASP.NET JSON za pomocą GWT

Piotr Owsiak
źródło
2
Możesz po prostu przekazać klientowi znacznik czasu i zadzwonić new Date()do niego.
jAndy
Gdybym miał znacznik czasu mógłbym, ale mam JSON, którego JavaScript najwyraźniej nie rozumie [sic!]
Piotr Owsiak

Odpowiedzi:

51

Nie ma standardowej reprezentacji dat w formacie JSON. Powinieneś zrobić to, co sugerował @jAndy i w ogóle nie serializować DateTime; po prostu wyślij ciąg daty RFC 1123 ToString("r")lub liczbę sekund od-epoki-systemu Unix, lub coś innego, czego możesz użyć w JavaScript do skonstruowania pliku Date.

Jakub
źródło
3
Dzięki, że szedłem martwą ścieżką, jako pierwszy zauważyłeś, że JSON nie obsługuje typu Date.
Piotr Owsiak
3
JSON obsługuje liczby, ciągi znaków, obiekty, tablice i literały true, false i null. Ponieważ Date nie jest żadnym z tych elementów, jest to typ złożony, który powinien być przechowywany jako obiekt, a nie jako ciąg, więc możesz dołączyć informacje o typie, takie jak nazwa typu, do specjalnych elementów członkowskich, takich jak „$ type”, które nigdy nie zostaną rozwiązane na prawdziwy członek obiektu. Takie meta-składowe mogą służyć do późniejszego przywrócenia obiektu JSON do obiektu środowiska wykonawczego o jednoznacznie określonym typie. Myślę, że praktyka umieszczania daty w łańcuchu jest głupia, ponieważ niepotrzebnie tworzy zarezerwowane wzory ciągów i próbuje dopasować je do każdego ciągu.
Triynko
4
Obecnie istnieje standardowy format daty JSON. tools.ietf.org/html/rfc7493#section-4.3
Bryan Larsen,
128

JSON.parseFunkcja przyjmuje opcjonalną funkcją DateTime reviver. Możesz użyć takiej funkcji:

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

Wtedy zadzwoń

JSON.parse(somejsonstring, dateTimeReviver);

A twoje daty wyjdą dobrze.

Tim
źródło
1
Dobrze zauważony, całkiem przydatny.
noup
5
Ta praktyka kodowania nieprymitywnych wpisanych danych w typie pierwotnym (łańcuch) jest szalona. Zakoduj daty w obiekcie JSON o znaczących właściwościach lub, aby przejść jeszcze dalej, dołącz właściwość „$ type” w obiekcie JSON, aby procedura analizy / deserializacji mogła odpowiednio ożywić typ, a nawet użyć niestandardowych konwerterów, jeśli chcesz spakować wszystko informacje w pojedynczą wartość właściwości, np. „ticks” lub „ms_since_epoch”.
Triynko
7
Musiałem zmodyfikować wyrażenie regularne w ten sposób / \ / Date ((-? \ D *)) \ //, aby było w stanie obsługiwać również liczby ujemne. Liczby ujemne pojawiają się, gdy masz bardzo starą datę i godzinę (sprzed Epoki), która została przekonwertowana przez .NET na format JSON.
ClearCloud 8
@ ClearCloud8: Tęsknisz za ukośnikami: / \ / Date \ ((-? \ D *) \) \ //
Jerther
1
Nigdy nie wiedziałem o tej funkcji - to takie przydatne!
keldar
50

Ta odpowiedź od Roya Tinkera tutaj :

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

Jak mówi: Funkcja substr pobiera część „/ Date (”), a funkcja parseInt pobiera liczbę całkowitą i ignoruje znak „) /” na końcu. Wynikowa liczba jest przekazywana do konstruktora Date.

Inną opcją jest prawidłowe sformatowanie informacji po stronie ASP, tak aby JavaScript mógł je łatwo odczytać. Rozważ zrobienie tego dla swoich dat:

DateTime.Now()

Która powinna zwrócić taki format:

7/22/2008 12:11:04 PM

Jeśli przekażesz to do Datekonstruktora JavaScript, takiego jak ten:

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

Zmienna datema teraz tę wartość:

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

Oczywiście, możesz sformatować ten DateTimeobiekt na dowolny ciąg / int, który Dateakceptuje konstruktor JS .

treeface
źródło
Dzięki treeface, ta odpowiedź pomogła mi ostatnio w czymś!
Malice
4
Nigdy, przenigdy nie polegaj na domyślnych formatach konwersji ciągów daty <->. Używanie milisekund od Epoki, które pozostają w domenie typów liczbowych, jest znacznie prostsze i bardziej niezawodne.
Johan Boulé
2
Ta odpowiedź przedstawia dwa rozwiązania - pierwsze jest poprawne (parseInt), a drugie błędne, więc nie jestem pewien, czy głosować za, czy przeciw! Problem z wyprowadzeniem po prostu jako ciągu polega na tym, że data może łatwo odwrócić się do tyłu, jeśli serwer znajduje się w jednym kraju, np. W USA, a przeglądarka w innym, np. W Wielkiej Brytanii.
mike nelson
Pierwsza odpowiedź, która da mi jakąś wskazówkę
Nick.McDermaid
Dobra odpowiedź aż do „ Rozważ zrobienie tego dla swoich randek… ”. Sugerowanie niestandardowego formatu, który wprowadza parsowanie zależne od implementacji i problemy ze strefą czasową, nie jest dobrym pomysłem. Format OP jest preferowany (choć nie jest idealny).
RobG
21

jeśli używasz daty ISO8601 w stylu JavaScript w JSON, możesz użyć tego z MDN

var jsonDate = (new Date()).toJSON();
var backToDate = new Date(jsonDate);
console.log(jsonDate); //2015-10-26T07:46:36.611Z
LeeGee
źródło
2
imo to najbardziej elegancka odpowiedź i powinna być akceptowana.
John
1
Rzeczywiście bardzo eleganckie, ale nie dotyczy to konkretnego formatu daty, o którym była mowa w pytaniu.
asiop
@aslop - jeśli użytkownik nie może przekonwertować daty na / z ISO, to JSON jest najmniejszym problemem.
LeeGee,
7

Możesz przekonwertować datę JSON na normalny format daty w JavaScript.

var date = new Date(parseInt(jsonDate.substr(6)));
ViPuL5
źródło
6

Co jest źle z:

new Date(1293034567877);

To wraca dla mnie „środa, 22 grudnia 2010 16:16:07 GMT + 0000 (czas standardowy GMT)”.

Czy potrzebujesz wydobyć numer z json?

Psytronic
źródło
3
Co jest nie tak z twoim rozwiązaniem? Cóż, 1293034567877 to nie JSON, który mam, prawda? Nie muszę też pobierać numeru z JSON, muszę pobrać datę z JSON. Oczekuję od JavaScript trochę więcej niż tylko możliwości robienia wszystkiego za pomocą wyrażenia regularnego. Potrzebuję, aby mój kod był czytelny i nie wyglądał jak klątwa z kreskówek.
Piotr Owsiak
7
Winiłbym .NET za stworzenie serializacji obiektu daty w formacie tak dziwnym jak \/Date(1293034567877)\/. Gdyby to było rozsądne, po prostu wyprowadziłoby czas epoki i można by za jego pomocą zainicjować obiekt Date.
Quentin
2
@treeface: Jeśli JSON nie jest JavaScriptem, myślę, że za to powszechne nieporozumienie można obwiniać samouczki i książki. Tak czy inaczej, z przyjemnością zostaję poprawiony, naprawdę. Jeśli chodzi o twoją sugestię, że datę można przedstawić jako ciąg, mogę powiedzieć, że wszystko można przedstawić jako ciąg, prawda? Ale to nie ułatwiłoby nam pracy, ale strasznie bolesne i piekielne. Myślę, że mój problem wynika z faktu, że uważałem JSON za format serializacji (reklamowany jako zajmujący mniejszą przepustowość i działający lepiej z JavaScript niż XML). Jak się okazuje, nie jest, przynajmniej nie bezbolesny.
Piotr Owsiak
1
@treeface: Wyszukałem w Google twoje twierdzenie dotyczące JSON i dowiedziałem się, że JSON to JavaScript, w rzeczywistości jest to podzbiór JavaScript. Zobacz RFC # 4627 „The application / json Media Type for JavaScript Object Notation (JSON)” i poszukaj stwierdzenia: „Celem projektu JSON było, aby był minimalny, przenośny, tekstowy i zawierał podzbiór JavaScript.”. Teraz, kiedy o tym myślę, wydaje się to oczywiste, ponieważ w JSON można wywołać funkcję eval ().
Piotr Owsiak
1
@David Dorward: Wolałbym, aby dodatkowa złożoność została zaimplementowana głęboko w bibliotekach (albo .NET, Java, Ruby, Python lub na jakimkolwiek języku / platformie, na której jesteś), zamiast pozostawić szczegół do obsługi programisty. Pamiętaj również, że nie potrzebujesz obsługi typów danych logicznych i całkowitych w JSON, możesz po prostu umieścić je w łańcuchach, prawda? Czy możesz sobie wyobrazić, jak okropne byłoby uzyskanie czegokolwiek z JSON?
Piotr Owsiak
2

Wiem, że to bardzo stary wątek, ale chcę go opublikować, aby pomóc tym, którzy wpadną na to tak, jak ja.

jeśli nie zależy ci na używaniu skryptu innej firmy, możesz użyć momentu, js Następnie możesz użyć .format (), aby sformatować go do dowolnego celu.

Eman
źródło
2

Daktyle są zawsze koszmarem. Odpowiadając na twoje stare pytanie, być może jest to najbardziej elegancki sposób:

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

W eval konwertujemy nasz ciąg znaków na kod javascript. Następnie usuwamy „/”, a funkcja zamiany jest wyrażeniem regularnym. Gdy zaczniemy od nowego, nasze zdania wykona to:

new Date(1455418800000)

Jedną rzeczą, której zacząłem używać dawno temu, są długie wartości, które są reprezentowane przez tiki ... dlaczego? cóż, lokalizacja i przestań się zastanawiać, jak jest skonfigurowana data na każdym serwerze lub każdym kliencie. W rzeczywistości używam go również w bazach danych.

Być może jest już dość późno na tę odpowiedź, ale może pomóc każdemu tutaj.

Gabriel Andrés Brancolini
źródło
Przy okazji, mój angielski przez lata staje się gorszy niż kiedykolwiek ... ale wydaje mi się, że zrozumiałem siebie.
Gabriel Andrés Brancolini,
Twoja odpowiedź działa świetnie, pomogła mi wyjść z kłopotu. Dzięki.
BoredBsee
1

AngularJS również nie mógł przeanalizować /Date(xxxxxxxxxxxxx)/ciągu daty .NET JSON .

Po stronie rozwiązałem ten problem, formatując datę do reprezentacji ciągu ISO 8601 zamiast bezpośrednio zrzucać Dateobiekt ...

Oto przykład kodu ASP.NET MVC.

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

Próbowałem, RFC 1123ale to nie działa. Angular traktuje to jako ciąg znaków zamiast Date.

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

Nie używałem .Net do takich rzeczy. Jeśli udało ci się wydrukować coś podobnego do następującego, powinno działać.

Uwaga, chyba że analizujesz ten ciąg JSON w inny sposób lub oczekujesz tylko, że użytkownicy będą mieć nowoczesne przeglądarki z wbudowanym parserem JSON, musisz użyć struktury JS lub JSON2, aby przeanalizować ciąg JSON wyprowadzony przez serwer do prawdziwego JSON obiekt.

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

Link do Wiki

Nowoczesne przeglądarki, takie jak Firefox 3.5 i Internet Explorer 8, zawierają specjalne funkcje do analizowania JSON. Ponieważ natywna obsługa przeglądarki jest wydajniejsza i bezpieczniejsza niż eval (), oczekuje się, że natywna obsługa JSON zostanie uwzględniona w następnym standardzie ECMAScript. [6]


Link do pliku JSON2

Przykład na żywo

subhaze
źródło
Rozumiem, ale mój problem z JSON i typem daty polega na tym, że muszę jawnie wykonać „nową datę (”), co oznacza a) dodatkową pracę b) dodatkową wiedzę, którą należy przekazać konsumentowi. Jestem naprawdę rozczarowany, gdy dowiedziałem się, jak to jest obsługiwane i zasadniczo uważam to za błąd w specyfikacji JSON.
Piotr Owsiak
0

Odpowiedź na to pytanie brzmi: użyj nuget, aby uzyskać JSON.NET, a następnie użyj tego w swojej JsonResultmetodzie:

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

wewnątrz twojego widoku prosto zrób to w javascript:

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

Jeśli jest to wywołanie 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); });

Po JSON.parsewywołaniu możesz umieścić datę JSON w new Dateinstancji, ponieważ JsonConverttworzy odpowiednią instancję czasu ISO

Callum Linington
źródło
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
źródło
0

Jak wspomniał Callum, dla mnie najlepszym sposobem jest zmiana metody Controller na string zamiast JsonResult ”.

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

Z metody Ajax możesz zrobić coś takiego

 $.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
źródło
0

używanie funkcji eval działa tylko po to, aby usunąć ukośnik z przodu iz tyłu.

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

daje czwartek 01 stycznia 1970 00:00:00 GMT-0700 (amerykański czas górski standardowy)

vernmic
źródło
0

Napotkałem problem z zewnętrznym API podającym daty w tym formacie, czasami nawet z informacjami o różnicy UTC, takimi jak /Date(123232313131+1000)/. Udało mi się obrócić Dateobiekt js za pomocą następującego kodu

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
źródło
-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
źródło
2
O ile rozumiem kod, nie zwracasz obiektu daty.
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;
};

// Użyj tej funkcji

var objDate=parseJsonDate("\/Date(1443812400000)\/");
alert(objDate);
Muzafar Hasan
źródło