moment.js - UTC ระบุวันที่ผิด


95

เหตุใด moment.js UTC จึงแสดงวันที่ผิดเสมอ ตัวอย่างเช่นจากคอนโซลนักพัฒนาของ Chrome:

moment(('07-18-2013')).utc().format("YYYY-MM-DD").toString()
// or
moment.utc(new Date('07-18-2013')).format("YYYY-MM-DD").toString()

ทั้งคู่จะกลับมาใน"2013-07-17"เหตุใดจึงกลับมาในวันที่ 17แทนที่จะเป็นวันที่ 18ที่ผ่านมา

แต่ถ้าฉันใช้ momentjs โดยไม่มี utc:

moment(new Date('07-18-2013')).format("YYYY-MM-DD").toString()

ฉันได้รับคืน"2013-07-18"ซึ่งเป็นสิ่งที่ฉันคาดหวังเมื่อใช้ moment.js UTC

หมายความว่าเราไม่สามารถหาวันที่ที่ถูกต้องได้เมื่อใช้ moment.js UTC?


4
ฉันไม่คิดว่าคุณต้องการtoString()หลังจากนั้นformat()(มันส่งคืนสตริงแล้ว)
alex

คำตอบ:


160

ตามค่าเริ่มต้น MomentJS จะแยกวิเคราะห์ตามเวลาท้องถิ่น หากระบุเฉพาะสตริงวันที่ (ไม่มีเวลา) เวลาเริ่มต้นคือเที่ยงคืน

ในรหัสของคุณคุณสร้างวันที่ในท้องถิ่นจากนั้นแปลงเป็นเขตเวลา UTC (อันที่จริงมันทำให้อินสแตนซ์ช่วงเวลาเปลี่ยนเป็นโหมด UTC ) ดังนั้นเมื่อมีการจัดรูปแบบจะถูกเลื่อน (ขึ้นอยู่กับเวลาท้องถิ่นของคุณ) ไปข้างหน้าหรือ ถอยหลัง.

หากเขตเวลาท้องถิ่นคือ UTC + N (N เป็นจำนวนบวก) และคุณแยกวิเคราะห์สตริงวันที่เท่านั้นคุณจะได้รับวันที่ก่อนหน้า

ต่อไปนี้คือตัวอย่างบางส่วนที่จะแสดงให้เห็น (การชดเชยเวลาท้องถิ่นของฉันคือ UTC + 3 ในช่วง DST):

>>> moment('07-18-2013', 'MM-DD-YYYY').utc().format("YYYY-MM-DD HH:mm")
"2013-07-17 21:00"
>>> moment('07-18-2013 12:00', 'MM-DD-YYYY HH:mm').utc().format("YYYY-MM-DD HH:mm")
"2013-07-18 09:00"
>>> Date()
"Thu Jul 25 2013 14:28:45 GMT+0300 (Jerusalem Daylight Time)"

หากคุณต้องการให้สตริงวันที่ - เวลาตีความเป็น UTC คุณควรระบุให้ชัดเจน:

>>> moment(new Date('07-18-2013 UTC')).utc().format("YYYY-MM-DD HH:mm")
"2013-07-18 00:00"

หรือตามที่ Matt Johnson กล่าวไว้ในคำตอบของเขาคุณสามารถ ( และน่าจะ ) แยกวิเคราะห์เป็นวันที่ UTC ตั้งแต่แรกโดยใช้moment.utc()และรวมสตริงรูปแบบเป็นอาร์กิวเมนต์ที่สองเพื่อป้องกันความคลุมเครือ

>>> moment.utc('07-18-2013', 'MM-DD-YYYY').format("YYYY-MM-DD HH:mm")
"2013-07-18 00:00"

ในการเปลี่ยนวันที่ UTC เป็นวันที่ท้องถิ่นคุณสามารถใช้local()วิธีการดังต่อไปนี้:

>>> moment.utc('07-18-2013', 'MM-DD-YYYY').local().format("YYYY-MM-DD HH:mm")
"2013-07-18 03:00"

ขอบคุณมาก. โดยพื้นฐานแล้วฉันควรผ่านเวลาเสมอเมื่อใช้ UTC หรือผ่านใน UTC เช่นเดียวกับแนวทางที่สองของคุณ
brg

อย่างใดอย่างหนึ่งหรือยึดตามเขตเวลาท้องถิ่น หากคุณส่งเวลาจากเซิร์ฟเวอร์คุณสามารถแสดงเป็น Unix timestamp (X) หรือเป็นสตริงในเขตเวลาที่กำหนด เหตุใดจึงต้องใช้ UTC แทนเขตเวลาท้องถิ่นของผู้ใช้ (ยกเว้นเพื่อวัตถุประสงค์ในการส่งข้อมูลปกติไปยังเซิร์ฟเวอร์)
MasterAM

1
โปรดทราบว่าnew Date('07-18-2013 UTC')จะไม่ทำงานใน IE8 หากคุณสนใจ
Dzmitry Lazerka

2
ฉันดิ้นรนกับเรื่องนี้มานานแล้ว พวกเขาควรอธิบายสิ่งนี้ได้ดีในไซต์ของพวกเขาเนื่องจากฉันคิดว่านี่เป็นกรณีการใช้งานที่พบบ่อยที่สุดของ moment.js ขอบคุณมาก! คุณช่วยผิวของฉันจริงๆ!
WebWanderer

รหัสนี้ใช้ได้กับฉัน: [code] moment (strDate, 'DD / MM / YYYY h: mm A'). utc (strDate) .format ("YYYY-MM-DD HH: mm") [/ code]
Omar Isaid

36

ทั้งสองDateและmomentจะแยกวิเคราะห์สตริงอินพุตในเขตเวลาท้องถิ่นของเบราว์เซอร์ตามค่าเริ่มต้น อย่างไรก็ตามDateบางครั้งก็ไม่สอดคล้องกับเรื่องนี้ ถ้า string เป็นพิเศษYYYY-MM-DDโดยใช้ยัติภังค์หรือถ้ามันเป็นYYYY-MM-DD HH:mm:ssก็จะตีความว่ามันเป็นเวลาท้องถิ่น ซึ่งแตกต่างจากDate, momentมักจะสอดคล้องกันเกี่ยวกับวิธีการแยกวิเคราะห์

วิธีที่ถูกต้องในการแยกวิเคราะห์ช่วงเวลาอินพุตเป็น UTC ในรูปแบบที่คุณระบุจะเป็นดังนี้:

moment.utc('07-18-2013', 'MM-DD-YYYY')

อ้างถึงเอกสารนี้

หากคุณต้องการจัดรูปแบบให้แตกต่างกันสำหรับเอาต์พุตคุณจะทำสิ่งนี้:

moment.utc('07-18-2013', 'MM-DD-YYYY').format('YYYY-MM-DD')

คุณไม่จำเป็นต้องโทรtoStringอย่างชัดเจน

โปรดทราบว่าการจัดเตรียมรูปแบบอินพุตเป็นสิ่งสำคัญมาก หากไม่มีวันที่เช่นนี้01-04-2013อาจได้รับการประมวลผลเป็นวันที่ 4 มกราคมหรือ 1 เมษายนทั้งนี้ขึ้นอยู่กับการตั้งค่าวัฒนธรรมของเบราว์เซอร์


เพียงเพื่อการเรียนรู้ในคอนโซล: moment.utc ('2013-07-18 0:00 +0100', 'YYYY-MM-DD HH: mm')ให้ฉัน"2013-07-18 0:00 +0100 "แต่สิ่งที่ dislpays บน jsfiddle เมื่อวิ่งที่แตกต่างกันนั่นคือ: พฤหัสบดี 25 กรกฎาคม 2013 01:00:00 GMT + 0100หมายเหตุ01:00:00 ขอบคุณ.
brg

การแสดงผลดิบmomentบนคอนโซลไม่มีประโยชน์มากนัก คุณอาจกำลังดูคุณสมบัติภายในอย่างใดอย่างหนึ่ง คุณควรจัดรูปแบบก่อนตรวจสอบผลลัพธ์ ตัวอย่างเช่นmoment.utc().format()หรือmoment().format().
Matt Johnson-Pint

ทั้งวันที่และช่วงเวลาจะแยกวิเคราะห์สตริงอินพุตในเขตเวลาท้องถิ่นของเบราว์เซอร์ตามค่าเริ่มต้น ตอนนี้ฉันใช้ EDT new Date('2010-12-12')ให้ฉันDate {Sat Dec 11 2010 19:00:00 GMT-0500 (Eastern Daylight Time)}ใน FF 38.0.5 เพียงเพื่อระบุบริบทว่า "ในเวลาท้องถิ่น" หมายถึงอะไร - ในกรณีนี้ดูเหมือนว่าจะหมายความว่า" Dateจะถือว่าสตริงที่ไม่มีเขตเวลาอยู่ใน UTC และจะแยกวิเคราะห์เป็นเวลาท้องถิ่น" d.getUTCDate()= 12and d.getDate()=11
ruffin

1
ใช่มีข้อยกเว้นบางประการ ES5 (เบราว์เซอร์ปัจจุบันส่วนใหญ่) จะตีความวันที่ด้วยยัติภังค์เป็น UTC แต่ทุกอย่างอื่น ๆ จะตีความเป็นเวลาท้องถิ่น ES6 กำลังเปลี่ยนพฤติกรรมนี้เพื่อตีความสตริงเดียวกันกับเวลาท้องถิ่น ฉันอัปเดตคำตอบแล้ว
Matt Johnson-Pint

ฮ่า ๆ เพิ่งเจอสิ่งนี้ที่ MDNบอกตรงๆว่า ( '2012-12-12'คือ UTC b / c อยู่ในรูปแบบ ISO แต่'December 12, 2012'และยัง'2012/12/12'แยกวิเคราะห์ด้วยเขตเวลาท้องถิ่นใน ES5) แต่คุณเอาชนะฉันไปแล้ว เยี่ยมมากที่ ES6 ทำให้พวกเขาทุกคนในท้องถิ่น [เขาพูดอย่างประชดประชัน] วันที่เป็นความเจ็บปวด (c) Advent of Dates
ruffin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.