Tại sao “2016-02-16” không bằng “2016-02-16 00:00”?


96

Tôi đang cố gắng chuyển cả hai chuỗi ngày sang new Date(t).

Tôi mong đợi cả hai chuỗi đại diện cho cùng một thời gian, nếu tôi bỏ qua thời gian, nó sẽ không phải là nửa đêm của ngày hôm đó?

Nhưng trong khi,

new Date("2016-02-16 00:00")

trả về ngày 16 tháng 2 năm 2016, nửa đêm, giờ địa phương như mong đợi,

new Date("2016-02-16")

trả về 2016-02-16, nửa đêm UTC, sai hoặc ít nhất không phải những gì tôi mong đợi với những gì chuỗi khác phân tích cú pháp.

Tôi sẽ hiểu điều đó nếu cả hai đều có cùng hành vi, cho dù đó là trả lại thời gian là giờ địa phương hay UTC, nhưng có vẻ như rất mâu thuẫn tại sao họ lại trả về những thứ khác nhau như thế này.

Để giải quyết vấn đề này, bất cứ khi nào tôi gặp một ngày không có dấu thời gian tương ứng, tôi có thể thêm "00:00" để có được hành vi nhất quán, nhưng có vẻ như điều này khá mong manh.

Tôi đang nhận giá trị này từ phần tử INPUT, thuộc loại 'datetime-local', vì vậy, có vẻ như đặc biệt không nhất quán rằng tôi phải làm việc xung quanh một giá trị được trả về bởi một phần tử trang.

Tôi đang làm gì đó sai, hay tôi nên làm điều gì đó khác đi?


2
2016-02-16 00:00- điều này không giống thời gian hợp lệ chút nào. ecma-international.org/ecma-262/6.0/... , nhưng ngay cả sau khi bạn đặt Tcó nó thực sự cư xử khác nhau
zerkms

Làm thế nào chính xác là bạn hiện đang lấy đối tượng Ngày từ phần tử đầu vào dựa trên giá trị của nó?
BoltClock

4
Theo tiêu chuẩn - "Nếu không có trường HH, mm hoặc ss" thì "00" được sử dụng làm giá trị và giá trị của trường sss vắng mặt là "000". Nếu không có chênh lệch múi giờ, ngày-giờ được hiểu là giờ địa phương. " --- nó sẽ hoạt động giống nhau.
zerkms

@BoltClock Hmm, có vẻ như nó đang lấy trường giá trị của phần tử và (như zerkms đã nhận thấy) loại bỏ chữ T vì một số lý do (tôi nghĩ vì giá trị đang được hiển thị cho người dùng trong ngữ cảnh mà "T" sẽ gây nhầm lẫn)
Michael

1
@Michael: Tuyệt vời. Trình duyệt kỳ quặc như thế này là yêu thích của tôi. (Hoặc nó có thể là một câu hỏi đặc tả DOM? Không có ý tưởng, tôi chưa thực sự xem xét.)
BoltClock

Câu trả lời:


100

Đó là những gì đặc tả ES5.1 nói phải làm:

Giá trị của độ lệch múi giờ vắng mặt là "Z".

Nó cũng nói:

Trước tiên, hàm cố gắng phân tích cú pháp định dạng của Chuỗi theo các quy tắc được gọi trong Định dạng Chuỗi Ngày Giờ (15.9.1.15). Nếu Chuỗi không phù hợp với định dạng đó, hàm có thể trở về bất kỳ định dạng ngày tháng cụ thể cho việc triển khai hoặc triển khai cụ thể.

Vì định dạng yêu cầu Tdấu phân cách giữa ngày và giờ, thời gian hợp lệ chuyển sang UTC:

> new Date("2016-02-16T00:00:00")
Tue Feb 16 2016 01:00:00 GMT+0100 (CET)
> new Date("2016-02-16")
Tue Feb 16 2016 01:00:00 GMT+0100 (CET)

... trong khi ở node.js, thời gian không hợp lệ (không có dấu phân tách T) dường như chuyển đến thời gian cục bộ cụ thể của việc triển khai:

> new Date("2016-02-16 00:00:00")
Tue Feb 16 2016 00:00:00 GMT+0100 (CET)

Lưu ý rằng ES6 đã thay đổi điều này, trong cùng một phần của tài liệu, nó thay đổi thành:

Nếu không có chênh lệch múi giờ, ngày-giờ được hiểu là giờ địa phương.

Niềm vui vỡ òa thay đổi .

Biên tập

Theo TC39 , thông số kỹ thuật được hiểu là các chuỗi ngày và giờ không có múi giờ (ví dụ: "2016-02-16T00: 00: 00") được coi là cục bộ (theo ISO 8601), nhưng chỉ chuỗi ngày (ví dụ: "2016-02-16") dưới dạng UTC (không phù hợp với ISO 8601).


20
Quả thực là niềm vui vỡ òa. Trong bản dự thảo mới của tiêu chuẩn ES7, một phần thay đổi từ UTC thành giờ địa phương đã được hoàn nguyên . Tiêu chuẩn mới cho biết ngày nên được hiểu là UTC nếu không có múi giờ nào được chỉ định, trong khi ngày-giờ phải được hiểu là giờ địa phương nếu không có múi giờ được quy định.
hichris123

3
Chúng thực sự phải là giờ địa phương, bất kể hình thức chỉ ngày hoặc giờ. Đó là cách ISO8601 hoạt động. Thật nực cười khi hình thức chỉ ngày được hiểu là UTC nửa đêm, vì một ngày UTC vượt thời gian thậm chí không có ý nghĩa về mặt khái niệm. Đã có một cuộc tranh luận sôi nổi về điều này tại ECMA tc39. Tôi đã chiến đấu vì giờ địa phương, và đã thua. github.com/tc39/ecma262/issues/87
Matt Johnson-Pint

10

Theo các thông số kỹ thuật :

Trước tiên, hàm cố gắng phân tích cú pháp định dạng của Chuỗi theo các quy tắc được gọi trong Định dạng Chuỗi Ngày Giờ (15.9.1.15). Nếu Chuỗi không phù hợp với định dạng đó, hàm có thể trở về bất kỳ định dạng ngày tháng cụ thể cho việc triển khai hoặc triển khai cụ thể.

Định dạng chuỗi ngày giờ chấp nhận 2016-02-16là ngày hợp lệ

Định dạng này bao gồm các biểu mẫu chỉ ngày:

YYYY
YYYY-MM
YYYY-MM-DD

[...] Nếu trường HH, mm hoặc ss vắng mặt, “00” được sử dụng làm giá trị và giá trị của trường sss vắng mặt là “000”. Giá trị của độ lệch múi giờ vắng mặt là "Z".

Do đó 2016-02-16dịch sang 2016-02-16T00:00:00.000Z.

Ngày khác 2016-02-16 00:00không phù hợp với định dạng và do đó việc phân tích cú pháp của nó là việc triển khai cụ thể. Rõ ràng, những ngày như vậy được coi là có múi giờ địa phương và ngày mẫu của bạn sẽ trả về các giá trị khác nhau tùy thuộc vào múi giờ:

/* tz = +05:00 */ new Date("2016-02-16 00:00").toISOString() // 2016-02-15T19:00:00.000Z
/* tz = -08:00 */ new Date("2016-02-16 00:00").toISOString() // 2016-02-16T08:00:00.000Z

Tóm lược:

  • Đối với các định dạng ngày giờ phù hợp, hành vi được xác định rõ - trong trường hợp không có múi giờ bù đắp, chuỗi ngày được coi là UTC (ES5) hoặc cục bộ (ES6).
  • Đối với các định dạng ngày giờ không phù hợp, hành vi được triển khai cụ thể - trong trường hợp không có múi giờ bù đắp, hành vi thông thường là coi ngày là cục bộ.
  • Trên thực tế, việc triển khai có thể chọn quay lại NaNthay vì cố gắng phân tích cú pháp các ngày không phù hợp. Chỉ cần kiểm tra mã của bạn trong Internet Explorer 11;)

7

Có lẽ bạn đang gặp phải sự khác biệt giữa triển khai ES5, ES6 và kết quả mong đợi của bạn. Per Date.parse tại MDN, "đặc biệt là trên các triển khai ECMAScript khác nhau trong đó các chuỗi như" 2015-10-12 12:00:00 "có thể được phân tích cú pháp thành NaN, UTC hoặc múi giờ địa phương" là quan trọng.

Thử nghiệm bổ sung trong Firefox 44 và IE 11 cho thấy cả hai đều trả về một đối tượng ngày tháng new Date("2016-02-16 00:00"), đối tượng này trả về NaN khi cố gắng lấy giá trị thành phần ngày và giá trị toString của nó là "Ngày không hợp lệ" (không phải "NaN"). Do đó, việc thêm "00:00 để có được hành vi nhất quán" có thể dễ dàng bị phá vỡ trong các trình duyệt khác nhau.

Như đã lưu ý trong các câu trả lời khác new Date("2016-02-16")sử dụng độ lệch múi giờ bằng 0 theo mặc định, tạo ra UTC lúc nửa đêm thay vì cục bộ.


OP dường như nhận được các kết quả khác nhau trên cùng một triển khai.
Salman A

6

Mỗi DateParser::Parse()mã nguồn V8 cho Chrome.

ES5 ISO 8601 ngày:

[('-'|'+')yy]yyyy[-MM[-DD]][THH:mm[:ss[.sss]][Z|(+|-)hh:mm]]

Một số không có dấu theo sau là ':' là giá trị thời gian và được thêm vào TimeComposer.

múi giờ mặc định thành Z nếu thiếu

> new Date("2016-02-16 00:00")
  Tue Feb 16 2016 00:00:00 GMT+0800 (China Standard Time)

Một chuỗi phù hợp với cả hai định dạng (ví dụ 1970-01-01) sẽ được phân tích cú pháp thành chuỗi ngày-giờ ES5 - có nghĩa là nó sẽ mặc định là UTC time-zone. Điều đó không thể tránh khỏi nếu tuân theo đặc điểm kỹ thuật của ES5.

> new Date("2016-02-16")
Tue Feb 16 2016 08:00:00 GMT+0800 (China Standard Time)

3

trả về 2016-02-16, nửa đêm UTC, sai hoặc ít nhất không phải những gì tôi mong đợi với những gì chuỗi khác phân tích cú pháp.

Nó thêm chênh lệch múi giờ vào 00:00

new Date("2016-02-16") đầu ra Tue Feb 16 2016 05:30:00 GMT+0530 (India Standard Time)

Múi giờ của tôi là IST với giá trị chênh lệch (tính bằng phút) +330, do đó, múi giờ đã thêm 330 phút thành 00:00.

Theo ecma-262, phần 20.3.3.2 Date.parse (chuỗi)

Nếu kết quả ToString hoàn thành đột ngột, Bản ghi Hoàn thành sẽ được trả về ngay lập tức. Nếu không, phân tích cú pháp sẽ diễn giải Chuỗi kết quả dưới dạng ngày và giờ; nó trả về một Số, giá trị thời gian UTC tương ứng với ngày và giờ. Chuỗi có thể được hiểu là giờ địa phương, giờ UTC hoặc thời gian ở một số múi giờ khác, tùy thuộc vào nội dung của Chuỗi.

Khi bạn đặt rõ ràng các đơn vị thời gian new Date("2016-02-16 00:00")mà nó sẽ sử dụng, hãy đặt nó là hoursminutes,

Nếu không, như đã nêu ở đây trong 2 0.3.1.16

Nếu không có chênh lệch múi giờ, ngày-giờ được hiểu là giờ địa phương.


Có nhưng tại sao nó làm được điều này trong một trường hợp mà không phải trong trường hợp khác?
Michael


Vậy tại sao đó lại là những kết quả khác nhau? Tiêu chuẩn tuyên bố nó phải giống nhau
zerkms

@zerkms Standard cho biết nó sẽ làm gì khi bạn vượt qua các đơn vị thời gian, nó không cho biết nó sẽ làm gì khi bạn không làm như vậy. Nó nói rõ ràng Nó The String may be interpreted as a local time, a UTC time, or a time in some other time zone, depending on the contents of the String.đang tuyên bố rằng nó phải giống nhau ở đâu?
gurvinder372

@ gurvinder372 Tôi đã cung cấp trích dẫn trong phần nhận xét câu hỏi: "Nếu trường HH, mm hoặc ss vắng mặt," 00 "được sử dụng làm giá trị và giá trị của trường sss vắng mặt là" 000 ". Nếu múi giờ chênh lệch vắng mặt, ngày-giờ được hiểu là giờ địa phương. "
zerkms
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.