moment.js - UTC đưa ra ngày sai


94

Tại sao moment.js UTC luôn hiển thị sai ngày. Ví dụ từ bảng điều khiển dành cho nhà phát triển của chrome:

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

Cả hai người trong số họ sẽ trở lại "2013-07-17" tại sao nó trở lại ngày 17 thay vì ngày 18 , đã được thông qua.

Nhưng nếu tôi sử dụng momentjs mà không có utc:

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

Tôi nhận được trở lại "2013-07-18" , đó là những gì tôi cũng mong đợi khi sử dụng moment.js UTC.

Điều này có nghĩa là chúng ta không thể lấy ngày chính xác khi sử dụng giờ UTC của moment.js?


4
Tôi không nghĩ bạn cần toString()sau format()(nó đã trả về một chuỗi).
alex

Câu trả lời:


159

Theo mặc định, MomentJS phân tích cú pháp theo giờ địa phương. Nếu chỉ cung cấp chuỗi ngày (không có thời gian), thời gian sẽ mặc định là nửa đêm.

Trong mã của bạn, bạn tạo một ngày địa phương và sau đó chuyển đổi nó sang múi giờ UTC (trên thực tế, nó làm cho phiên bản thời điểm chuyển sang chế độ UTC ), vì vậy khi nó được định dạng, nó sẽ bị dịch chuyển (tùy thuộc vào giờ địa phương của bạn) về phía trước hoặc ngược.

Nếu múi giờ địa phương là UTC + N (N là một số dương) và bạn phân tích cú pháp chuỗi chỉ ngày, bạn sẽ nhận được ngày trước đó.

Dưới đây là một số ví dụ để minh họa điều đó (thời gian bù giờ địa phương của tôi là UTC + 3 trong 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)"

Nếu bạn muốn chuỗi ngày-giờ được hiểu là UTC, bạn nên nói rõ về nó:

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

hoặc, như Matt Johnson đã đề cập trong câu trả lời của mình, bạn có thể ( và có lẽ nên ) phân tích cú pháp nó thành ngày UTC ngay từ đầu bằng cách sử dụng moment.utc()và bao gồm chuỗi định dạng làm đối số thứ hai để ngăn chặn sự mơ hồ.

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

Để đi ngược lại và chuyển đổi ngày UTC thành ngày địa phương, bạn có thể sử dụng local()phương pháp như sau:

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

Cảm ơn nhiều. Vì vậy, về cơ bản, tôi nên luôn đúng lúc khi sử dụng UTC hoặc vượt qua UTC như trong cách tiếp cận thứ hai của bạn.
brg

Hoặc là hoặc dính vào múi giờ địa phương. Nếu bạn gửi thời gian từ máy chủ, bạn có thể biểu thị chúng dưới dạng dấu thời gian Unix (X) hoặc dưới dạng chuỗi tại múi giờ cụ thể. Tại sao lại sử dụng UTC thay vì múi giờ cục bộ của người dùng (ngoại trừ mục đích gửi dữ liệu chuẩn hóa đến máy chủ)?
MasterAM

1
Hãy lưu ý rằng nó new Date('07-18-2013 UTC')sẽ không hoạt động trong IE8, nếu bạn quan tâm.
Dzmitry Lazerka,

2
Tôi đã đấu tranh với điều này quá lâu. Họ thực sự nên giải thích rõ điều này trên trang web của họ, vì tôi cho rằng đây là trường hợp sử dụng phổ biến nhất của moment.js. Cảm ơn bạn rất nhiều! Bạn thực sự đã cứu làn da của tôi!
WebWanderer

mã này phù hợp với tôi: [code] moment (strDate, 'DD / MM / YYYY h: mm A'). utc (strDate) .format ("YYYY-MM-DD HH: mm") [/ code]
Omar Isaid

36

Cả hai Datemomentsẽ phân tích cú pháp chuỗi đầu vào theo múi giờ địa phương của trình duyệt theo mặc định. Tuy nhiên, Dateđôi khi không phù hợp với vấn đề này. Nếu cụ thể là chuỗi YYYY-MM-DDsử dụng dấu gạch ngang hoặc nếu có YYYY-MM-DD HH:mm:ss, nó sẽ diễn giải nó là giờ địa phương . Không giống như Date, momentsẽ luôn nhất quán về cách nó phân tích cú pháp.

Cách chính xác để phân tích cú pháp thời điểm đầu vào dưới dạng UTC ở định dạng bạn đã cung cấp sẽ như sau:

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

Tham khảo tài liệu này .

Nếu sau đó bạn muốn định dạng nó theo cách khác cho đầu ra, bạn sẽ làm như sau:

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

Bạn không cần phải gọi toStringmột cách rõ ràng.

Lưu ý rằng việc cung cấp định dạng đầu vào là rất quan trọng. Nếu không có nó, một ngày như01-04-2013 có thể được xử lý là ngày 4 tháng 1 hoặc ngày 1 tháng 4, tùy thuộc vào cài đặt văn hóa của trình duyệt.


Chỉ vì mục đích học tập, trong bảng điều khiển: moment.utc ('2013-07-18 0:00 +0100', 'YYYY-MM-DD HH: mm') cho tôi "2013-07-18 0:00 +0100 " Nhưng điều gì gây ra lỗi trên jsfiddle khi chạy thì khác đó là: Thứ 7 ngày 25 tháng 7 năm 2013 01:00:00 GMT + 0100 Lưu ý 01:00:00 . cảm ơn.
brg

Xuất bản thô momenttrên bảng điều khiển không hữu ích lắm. Có thể bạn đang xem một trong những thuộc tính bên trong của nó. Bạn nên định dạng nó trước khi kiểm tra kết quả. Ví dụ moment.utc().format()hoặc moment().format().
Matt Johnson-Pint,

Theo mặc định, cả Ngày và thời điểm sẽ phân tích cú pháp chuỗi đầu vào theo múi giờ địa phương của trình duyệt. Tôi đang sử dụng EDT ngay bây giờ. new Date('2010-12-12')cho tôi Date {Sat Dec 11 2010 19:00:00 GMT-0500 (Eastern Daylight Time)}trong FF 38.0.5. Chỉ để ngữ cảnh hóa chính xác "theo giờ địa phương" nghĩa là gì - trong trường hợp này, nó có vẻ có nghĩa là " Datesẽ giả sử một chuỗi không có múi giờ ở UTC và sẽ phân tích cú pháp thành giờ địa phương." d.getUTCDate()= 12d.getDate()=11
ruffin

1
Có, có một số ngoại lệ. ES5 (hầu hết các trình duyệt hiện tại) sẽ diễn giải ngày có dấu gạch nối là UTC, nhưng mọi thứ khác được hiểu là giờ địa phương. ES6 đang thay đổi hành vi này để diễn giải chuỗi tương tự như giờ địa phương. Tôi đã cập nhật câu trả lời.
Matt Johnson-Pint

Ha, yep, vừa mới gặp điều này ở MDN nói chính xác rằng ( '2012-12-12'UTC b / c nó ở định dạng ISO, nhưng 'December 12, 2012'và thậm chí '2012/12/12'được phân tích cú pháp với múi giờ địa phương trong ES5), nhưng bạn đã đánh bại tôi. Tuyệt vời đến mức ES6 làm cho tất cả chúng trở thành địa phương [anh ta nói một cách mỉa mai]. Ngày là một nỗi đau, (c) Advent of Dates
ruffin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.