วิธีแยกวิเคราะห์ 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 สิ่งที่ฉันพบคือโซลูชัน regex ที่น่าทึ่ง (มีข้อบกพร่องมากมาย)

เป็นเรื่องยากที่จะเชื่อว่าไม่มีโซลูชันที่สวยงามเนื่องจากทั้งหมดนี้อยู่ใน JavaScrip ฉันหมายถึงโค้ด JavaScript ที่พยายามอ่าน JSON (JavaScript Object Notation) ซึ่งควรจะเป็นรหัส JavaScript และในขณะนี้ปรากฎว่าไม่ใช่สาเหตุที่ JavaScript ไม่สามารถ ทำงานได้ดีที่นี่

ฉันยังเห็นโซลูชันการประเมินบางอย่างที่ฉันไม่สามารถใช้งานได้ (นอกจากถูกชี้ว่าเป็นภัยคุกคามด้านความปลอดภัย)

ไม่มีทางที่จะทำอย่างสวยหรูได้จริงหรือ?

คำถามที่คล้ายกันที่ไม่มีคำตอบจริง:
วิธีแยกวิเคราะห์รูปแบบ ASP.NET JSON Date ด้วย GWT


2
คุณสามารถส่งการประทับเวลาไปยังไคลเอนต์และโทรติดต่อnew Date()ได้
jAndy

ถ้าฉันมีการประทับเวลาฉันทำได้ แต่ฉันมี JSON ซึ่งดูเหมือนว่า JavaScript ไม่เข้าใจ [sic!]
Piotr Owsiak

คำตอบ:


51

ไม่มีการแสดงวันที่ JSON มาตรฐาน คุณควรทำในสิ่งที่ @jAndy แนะนำและไม่ทำให้เป็นอนุกรมDateTimeเลย เพียงแค่ส่งสตริงวันที่ RFC 1123 ToString("r")หรือหมายเลขวินาทีจาก Unix-epoch หรืออย่างอื่นที่คุณสามารถใช้ใน JavaScript เพื่อสร้างไฟล์Date.


3
ขอบคุณฉันกำลังเดินไปตามทางที่ตายคุณเป็นคนแรกที่ชี้ให้เห็นว่า JSON ไม่รองรับประเภทวันที่
Piotr Owsiak

3
JSON รองรับตัวเลขสตริงออบเจ็กต์อาร์เรย์และลิเทอรัลจริงเท็จและโมฆะ เนื่องจาก Date ไม่ใช่สิ่งเหล่านี้จึงเป็นประเภทที่ซับซ้อนซึ่งควรจัดเก็บเป็นอ็อบเจ็กต์แทนที่จะเป็นสตริงดังนั้นคุณสามารถรวมข้อมูลประเภทเช่นชื่อประเภทในสมาชิกพิเศษเช่น "$ type" ที่ไม่มีวันแก้ไขเป็น สมาชิกวัตถุจริง สมาชิกเมตาดังกล่าวสามารถใช้เพื่อฟื้นฟูอ็อบเจ็กต์ JSON เป็นอ็อบเจ็กต์รันไทม์ที่พิมพ์มากในภายหลัง ฉันคิดว่าการติดวันที่ในสตริงนั้นโง่เพราะสร้างรูปแบบสตริงที่สงวนไว้โดยไม่จำเป็นและพยายามจับคู่กับทุกสตริง
Triynko

4
ขณะนี้มีรูปแบบวันที่ JSON มาตรฐาน tools.ietf.org/html/rfc7493#section-4.3
Bryan Larsen

128

JSON.parseฟังก์ชั่นการทำงานที่ยอมรับ DateTime ฟื้นฟูตัวเลือก คุณสามารถใช้ฟังก์ชันเช่นนี้:

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 ด้วยคุณสมบัติที่มีความหมายหรือหากต้องการไปให้ไกลกว่านั้นให้รวมคุณสมบัติ "$ type" ในออบเจ็กต์ JSON เพื่อให้รูทีนแยกวิเคราะห์ / deserialize สามารถฟื้นฟูประเภทได้อย่างเหมาะสมและยังใช้ตัวแปลงที่กำหนดเองได้หากคุณต้องการแพ็คทั้งหมด ข้อมูลเป็นค่าคุณสมบัติเดียวเช่น "ticks" หรือ "ms_since_epoch"
Triynko

7
ฉันต้องแก้ไข regex เช่นนี้ / \ / Date ((-? \ d *)) \ // เพื่อที่จะสามารถจัดการกับจำนวนลบได้เช่นกัน ตัวเลขติดลบจะปรากฏขึ้นเมื่อคุณมี DateTime เก่ามาก (ก่อนยุค) ที่แปลงโดย. NET เป็น JSON
ClearCloud8

@ ClearCloud8: คุณพลาดเครื่องหมายทับกลับ: / \ / Date \ ((-? \ d *) \) \ //
Jerther

1
ฉันไม่เคยรู้เกี่ยวกับฟังก์ชันนี้มาก่อน - มีประโยชน์มาก!
keldar

50

คำตอบนี้จากRoy Tinker ที่นี่ :

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

ดังที่เขากล่าวว่า: ฟังก์ชัน substr จะดึงส่วน "/ Date (" ออกมาและฟังก์ชัน parseInt จะรับจำนวนเต็มและละเว้น ") /" ในตอนท้าย ตัวเลขผลลัพธ์จะถูกส่งไปยังตัวสร้างวันที่

อีกทางเลือกหนึ่งคือจัดรูปแบบข้อมูลของคุณให้ถูกต้องในด้าน 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 คำตอบนี้ช่วยฉันในบางสิ่งเมื่อเร็ว ๆ นี้!
Malice

4
ไม่เคยพึ่งพารูปแบบการแปลงสตริงวันที่เริ่มต้น <-> การใช้มิลลิวินาทีตั้งแต่ Epoch ซึ่งอยู่ในโดเมนประเภทตัวเลขนั้นง่ายและเชื่อถือได้มากกว่า
Johan Boulé

2
คำตอบนี้นำเสนอวิธีแก้ปัญหาสองวิธี - อันแรกถูกต้อง (parseInt) และอันที่สองผิดจึงไม่แน่ใจว่าจะโหวตเพิ่มหรือลดคะแนน! ปัญหาในการส่งออกเป็นสตริงคือวันที่สามารถพลิกกลับด้านหลังได้อย่างง่ายดายหากเซิร์ฟเวอร์อยู่ในประเทศหนึ่งเช่นสหรัฐอเมริกาและเบราว์เซอร์ในอีกประเทศหนึ่งเช่นสหราชอาณาจักร
ไมค์เนลสัน

คำตอบแรกที่จะให้เบาะแสกับฉัน
Nick.McD mermaid

คำตอบตกลงจนกว่าจะ " พิจารณาดำเนินการนี้สำหรับวันที่ของคุณ ... " การแนะนำรูปแบบที่ไม่เป็นมาตรฐานซึ่งแนะนำปัญหาการแยกวิเคราะห์และเขตเวลาที่ขึ้นอยู่กับการใช้งานไม่ใช่ความคิดที่ดี ควรใช้รูปแบบ 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

2
imo นี่คือคำตอบที่สวยหรูที่สุดและควรเป็นคำตอบที่ได้รับการยอมรับ
John

1
สวยหรูมาก แต่สิ่งนี้ไม่เกี่ยวข้องกับรูปแบบวันที่ที่ระบุในคำถาม
asiop

@aslop - หากผู้ใช้ไม่สามารถแปลงวันที่เป็น / จาก ISO ได้แสดงว่า JSON เป็นปัญหาน้อยที่สุด
LeeGee

7

คุณสามารถแปลง JSON Date เป็นรูปแบบวันที่ปกติใน JavaScript

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

6

เกิดอะไรขึ้นกับ:

new Date(1293034567877);

คืนนี้ให้ฉัน "พ. 22 ธ.ค. 2553 16:16:07 น. GMT + 0000 (เวลามาตรฐาน GMT)"

หรือว่าต้องเอาเลขออก json?


3
โซลูชันของคุณมีอะไรผิดปกติ 1293034567877 ไม่ใช่ JSON ที่ฉันมีใช่ไหม นอกจากนี้ฉันไม่จำเป็นต้องเอาหมายเลขออกจาก JSON ฉันต้องเอา Date ออกเป็น JSON ฉันคาดหวังว่าจะได้ประโยชน์จาก JavaScript มากกว่าการใช้ regex ได้ทุกอย่าง ฉันต้องการรหัสของฉันเพื่อให้อ่านได้และไม่ดูเหมือนคำสาปการ์ตูน
Piotr Owsiak

7
ฉันตำหนิ. NET ที่สร้างการทำให้เป็นอนุกรมของวัตถุวันที่ในรูปแบบที่แปลกพอ ๆ กับ\/Date(1293034567877)\/. ถ้ามันมีเหตุผลมันก็จะแสดงผลตามช่วงเวลาและคุณสามารถเริ่มต้นวัตถุวันที่ด้วยสิ่งนั้น
Quentin

2
@treeface: ถ้า JSON ไม่ใช่ JavaScript ฉันคิดว่าแบบฝึกหัดและหนังสือจะถูกตำหนิสำหรับความเข้าใจผิดทั่วไปนี้ อย่างไรก็ตามฉันยินดีที่ได้รับการแก้ไขจริงๆ สำหรับคำแนะนำของคุณว่า Date สามารถแสดงเป็น String ได้ผมบอกได้เลยว่าทุกอย่างสามารถแสดงเป็น String ได้ใช่ไหม? แต่สิ่งนี้จะไม่ทำให้งานของเราง่ายขึ้น แต่เป็นความเจ็บปวดและความชั่วร้ายอย่างมาก ฉันเดาว่าปัญหาของฉันเกิดจากการที่ฉันถือว่า JSON เป็นรูปแบบการทำให้เป็นอนุกรม (โฆษณาว่าใช้แบนด์วิดท์น้อยกว่าและทำงานกับ JavaScript ได้ดีกว่า XML) ปรากฎว่าไม่ใช่อย่างน้อยก็ไม่ใช่สิ่งที่เจ็บปวด
Piotr Owsiak

1
@treeface: ฉันอ้าง Google ของคุณเกี่ยวกับ JSON และพบว่า JSON เป็น JavaScript จริงๆแล้วมันเป็นส่วนย่อยของ JavaScript ดู RFC # 4627 "ประเภทสื่อแอปพลิเคชัน / json สำหรับ JavaScript Object Notation (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 เราแปลงสตริงของเราเป็นรหัสจาวาสคริปต์ จากนั้นเราลบ "/" ลงในฟังก์ชันแทนที่เป็นนิพจน์ทั่วไป เมื่อเราเริ่มต้นใหม่ประโยคของเราจะดำเนินการต่อไปนี้:

new Date(1455418800000)

ตอนนี้สิ่งหนึ่งที่ฉันเริ่มใช้เมื่อนานมาแล้วคือค่ายาวที่แสดงในเห็บ ... ทำไม? แปลเป็นภาษาท้องถิ่นและหยุดคิดในการกำหนดค่าวันที่ในทุกเซิร์ฟเวอร์หรือทุกไคลเอนต์ อันที่จริงฉันใช้มันมากเกินไปในฐานข้อมูล

บางทีอาจจะค่อนข้างช้าสำหรับคำตอบนี้ แต่สามารถช่วยใครก็ได้ที่นี่


Btw ภาษาอังกฤษของฉันในช่วงหลายปีที่ผ่านมาแย่ลงกว่าเดิม ... แต่ฉันเดาว่าฉันเข้าใจตัวเองแล้ว
Gabriel Andrés Brancolini

คำตอบของคุณใช้งานได้ดีช่วยให้ฉันไม่ติดขัด ขอบคุณ
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 ถือว่าสิ่งนี้เป็นสตริงแทน Date

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

ลิงค์วิกิ

เบราว์เซอร์สมัยใหม่เช่น Firefox 3.5 และ Internet Explorer 8 มีคุณลักษณะพิเศษสำหรับการแยกวิเคราะห์ JSON เนื่องจากการสนับสนุนเบราว์เซอร์แบบเนทีฟนั้นมีประสิทธิภาพและปลอดภัยมากกว่า eval () จึงคาดว่าการรองรับ JSON ดั้งเดิมจะรวมอยู่ในมาตรฐาน ECMAScript ถัดไป [6]


ลิงก์ไปยังไฟล์ JSON2

ตัวอย่างสด


ฉันเข้าใจแล้ว แต่ปัญหาของฉันเกี่ยวกับ JSON และประเภทวันที่คือฉันต้องทำ "วันที่ใหม่ (" ซึ่งเป็นงานพิเศษอย่างชัดเจน b) ความรู้เพิ่มเติมที่ต้องสื่อสารกับผู้บริโภค ฉันผิดหวังมากที่พบว่ามีการจัดการอย่างไรและฉันคิดว่ามันเป็นข้อผิดพลาดในข้อมูลจำเพาะ JSON
Piotr Owsiak

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 เป็นสตริงแทน 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));

ผลผลิตพฤ. 01 ม.ค. 2513 00:00:00 GMT-0700 (เวลามาตรฐานภูเขาของสหรัฐฯ)


0

ฉันวิ่งเข้าไปในปัญหากับภายนอก API /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);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.