Câu hỏi Phát hiện cá thể ngày “không hợp lệ” trong JavaScript


Tôi muốn nói sự khác biệt giữa các đối tượng ngày hợp lệ và không hợp lệ trong JS, nhưng không thể tìm ra cách:

var d = new Date("foo");
console.log(d.toString()); // shows 'Invalid Date'
console.log(typeof d); // shows 'object'
console.log(d instanceof Date); // shows 'true'

Bất kỳ ý tưởng nào để viết một isValidDate chức năng?

  • Ash đề nghị Date.parse để phân tích các chuỗi ngày tháng, cung cấp một cách có thẩm quyền để kiểm tra xem chuỗi ngày có hợp lệ hay không.
  • Điều tôi muốn, nếu có thể, là API của tôi chấp nhận một cá thể Date và để có thể kiểm tra / xác nhận xem nó có hợp lệ hay không. Giải pháp của Borgar làm điều đó, nhưng tôi cần kiểm tra nó trên các trình duyệt. Tôi cũng tự hỏi liệu có một cách thanh lịch hơn không.
  • Ash khiến tôi xem xét việc không chấp nhận API của mình Date trường hợp ở tất cả, điều này sẽ dễ nhất để xác nhận.
  • Borgar đề xuất thử nghiệm cho một Date và sau đó kiểm tra DateGiá trị thời gian. Nếu ngày không hợp lệ, giá trị thời gian là NaN. Tôi đã kiểm tra với ECMA-262 và hành vi này là trong tiêu chuẩn, đó là chính xác những gì tôi đang tìm kiếm.

1085
2017-08-30 11:34


gốc


Bạn có thể loại bỏ câu lệnh if bằng cách thay đổi phần thân của hàm thành: return ( Object.prototype.toString.call(d) === "[object Date]" && !isNaN(d.getTime()) ); - styfle
@styfle - đoán đó là một sở thích kiểu: Tôi tìm thấy nó rõ ràng hơn để tách kiểm tra kiểu từ logic bình đẳng. - orip
@orip discourse là chính xác những gì là rất khuyến khích trong các câu hỏi. Vui lòng tham khảo các chủ đề meta có liên quan để tìm hiểu lý do đằng sau nó. Đặt câu trả lời cho câu hỏi của riêng mình trong câu hỏi chính là chống lại chính sách trang web. OTOH, cảm ơn cho câu trả lời và có "EDIT" trong câu trả lời của bạn là fluff điển hình. Nếu bạn muốn bạn đánh giá cao câu hỏi để xác định bạn là một người không biết SO là gì và cách sử dụng nó, và không muốn biết điều đó - là khách của tôi. - vaxquis
@orip: Nó không phải là "mất"; nó vẫn còn lộn xộn lên lịch sử sửa đổi của câu hỏi nếu bạn muốn nhìn thấy nó một lần nữa. Nhưng nó không thuộc về một câu hỏi. Tại đại diện 37k, bạn nên biết điều này. - Lightness Races in Orbit
Vui lòng ngừng chiến tranh chỉnh sửa. Các chỉnh sửa về câu hỏi này được thảo luận meta. Xin vui lòng không chỉnh sửa / rollback bài đăng này hơn nữa. Nếu bạn không đồng ý với các chỉnh sửa / khôi phục trước đó hoặc có bất kỳ nhận xét nào về chúng, vui lòng đăng trên chuỗi meta đó chứ không phải ở đây. - Lundin


Các câu trả lời:


Đây là cách tôi sẽ làm điều đó:

if (Object.prototype.toString.call(d) === "[object Date]") {
  // it is a date
  if (isNaN(d.getTime())) {  // d.valueOf() could also work
    // date is not valid
  } else {
    // date is valid
  }
} else {
  // not a date
}

Cập nhật [2018-05-31]: Nếu bạn không quan tâm đến các đối tượng Date từ các bối cảnh JS khác (các cửa sổ bên ngoài, các khung hoặc các khung nội tuyến), biểu mẫu đơn giản này có thể được ưu tiên:

function isValidDate(d) {
  return d instanceof Date && !isNaN(d);
}

890
2017-08-30 11:48



Tại sao không "d instanceof Date" cho lần so sánh đầu tiên đó? - Chris Charabaruk
Chris: "d instance Date" cũng đúng cho ngày không hợp lệ - orip
instanceof phá vỡ trên các khung. Vịt gõ cũng có thể hoạt động tốt: validDate == d && d.getTime &&! IsNaN (d.getTime ()); - Vì câu hỏi là dành cho một chức năng tiện ích chung, tôi thích nghiêm ngặt hơn. - Borgar
@Borgar, chỉ tìm thấy câu trả lời của tôi: "Các vấn đề phát sinh khi nói đến kịch bản trong môi trường DOM nhiều khung. Tóm lại, các đối tượng mảng được tạo trong một iframe không chia sẻ [[Prototype]] với các mảng được tạo trong iframe khác Các hàm tạo của chúng là các đối tượng khác nhau và do đó cả kiểm tra instanceof và constructor đều thất bại. " - Ash
bạn thậm chí không cần d.getTime chỉ isNan(d) - TecHunter


Thay vì sử dụng new Date() bạn nên sử dụng:

var timestamp = Date.parse('foo');

if (isNaN(timestamp) == false) {
  var d = new Date(timestamp);
}

Date.parse() trả về dấu thời gian, một số nguyên biểu thị số mili giây kể từ 01 / Jan / 1970. Nó sẽ trở lại NaN nếu nó không thể phân tích chuỗi ngày tháng được cung cấp.


213
2017-08-30 11:47



1, rất tốt, cảm ơn! Date.parse trả về mili giây, không phải là một đối tượng Date, vì vậy sau khi thử nghiệm, chúng ta vẫn cần phải xây dựng một đối tượng Date từ nó (ngày mới (d)) - orip
Rất vui được trợ giúp, tôi đã chỉnh sửa câu trả lời để làm cho nó rõ ràng hơn, Date.parse trả về dấu thời gian tính bằng mili giây. - Ash
-1 Dunno tại sao điều này có rất nhiều phiếu bầu, Date.parse thực hiện phụ thuộc và chắc chắn không được tin cậy để phân tích cú pháp chuỗi ngày tháng chung. Không có định dạng duy nhất được phân tích cú pháp chính xác trong các trình duyệt phổ biến, ít hơn tất cả những định dạng được sử dụng (mặc dù cuối cùng là định dạng ISO8601 được chỉ định trong ES5 nên được ok). - RobG
điều này có thể hoạt động nhưng sẽ vẫn trả về các kết quả dương tính giả cho "02/31/2012" không hợp lệ - John
Hành vi của Date.parse không phải là tiêu chuẩn trên các trình duyệt - Genady Sergeev


Bạn có thể kiểm tra tính hợp lệ của Date vật d thông qua

d instanceof Date && isFinite(d)

Để tránh các vấn đề về khung hình chéo, người ta có thể thay thế instanceof kiểm tra với

Object.prototype.toString.call(d) === '[object Date]'

Cuộc gọi đến getTime() như trong Câu trả lời của Borgar là không cần thiết như isNaN() và isFinite() cả hai đều chuyển đổi hoàn toàn thành số.


88
2017-08-30 14:07



Hãy thử điều này trong chrome - Object.prototype.toString.call (ngày mới ("2013-07-09T19: 07: 9Z")). Nó sẽ trả về "[object date]". Theo bạn, do đó, "2013-07-09T19: 07: 9Z", phải là ngày hợp lệ. Nhưng nó không phải như vậy. Bạn có thể xác minh nó, một lần nữa trong chrome, bằng cách làm var dateStr = new Date ("2013-07-09T19: 07: 9Z"); dateStr Nó sẽ trả về ngày không hợp lệ. - Tintin
@ Tintin: đó là những gì isFinite() là cho - toString.call() chỉ là một sự thay thế cho instanceof một phần của séc - Christoph
Sẽ so sánh với '[object Date]' hoạt động với các trình duyệt không phải tiếng Anh? Tôi nghi ngờ điều đó. - kristianp
@ kristianp thực sự nó có thể sẽ và có lẽ là một phần của thông số ECMAScript. Nhưng, vâng, nó có vẻ xấu xí. - binki
Với tôi, cách tiếp cận đầu tiên ở đây là lựa chọn tốt nhất, mặc dù tôi không chắc liệu có bất kỳ lợi thế thực tế nào của việc sử dụng hay không isFinite kết thúc isNaN (cả hai đều hoạt động tốt với Date(Infinity)). Hơn nữa, nếu bạn muốn điều kiện ngược lại, nó sẽ đơn giản hơn một chút: if (!(date instanceof Date) || isNaN(date)). - Andrew


Giải pháp của tôi là chỉ cần kiểm tra xem bạn có nhận được một đối tượng ngày hợp lệ không:

Thực hiện

Date.prototype.isValid = function () {
    // An invalid date object returns NaN for getTime() and NaN is the only
    // object not strictly equal to itself.
    return this.getTime() === this.getTime();
};  

Sử dụng

var d = new Date("lol");

console.log(d.isValid()); // false

d = new Date("2012/09/11");

console.log(d.isValid()); // true

66
2017-09-11 15:03



isNaN là một cách rõ ràng hơn để kiểm tra NaN - orip
Tuy nhiên, bạn luôn tìm thấy những người viết các phiên bản của riêng họ :) documentcloud.github.com/underscore/docs/… - Ash Clarke
vì tôi tôn trọng underscore.js, điều này đã thúc đẩy một số nghiên cứu. isNaN("a") === true, trong khi ("a" !== "a") === false. Đó là giá trị suy nghĩ về. +1 - orip
Tôi đã thử nghiệm hiệu suất cho 3 giải pháp chính mà tôi đã tìm thấy ở đây. Xin chúc mừng, bạn là người chiến thắng! jsperf.com/detecting-an-invalid-date - zVictor
@Ali Đó là một đối tượng ngày hợp lệ. new Date("02-31-2000") // Thu Mar 02 2000 00:00:00 GMT+0000 (GMT Standard Time). Nếu bạn đang đi qua một chuỗi cho hàm tạo ngày, bạn phải vượt qua trong một chuỗi chuẩn hóa để có được một kết quả đáng tin cậy. Cụ thể, "Chuỗi phải ở định dạng được nhận dạng bởi phương thức Date.parse ()". developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… - Ash Clarke


câu trả lời ngắn nhất để kiểm tra ngày hợp lệ

if(!isNaN(date.getTime()))

49
2017-07-04 10:10



Điều này là hoàn hảo cho những gì tôi muốn. Cảm ơn! - Fred
Câu trả lời hay nhất. Mọi thứ khác là quá phức tạp hoặc không chính xác. - Polyducks
Vấn đề duy nhất là nếu ngày không thuộc loại Date; bạn gặp lỗi JS. - Andrew
@Andrew bạn cần tạo đối tượng ngày và nếu bạn đã có một đối tượng thì hãy sử dụng date && !isNaN(date.getTime()) - abhirathore2006
Đúng, giống như các câu trả lời khác từ 8 năm trước. : P stackoverflow.com/a/1353945/2321042 - Andrew


Bạn chỉ có thể sử dụng moment.js

Đây là một ví dụ:

var m = moment('2015-11-32', 'YYYY-MM-DD');
m.isValid(); // false

Các phần xác nhận trong tài liệu khá rõ ràng.

Ngoài ra, các cờ phân tích cú pháp sau sẽ dẫn đến ngày không hợp lệ:

  • overflow: Một tràn của một lĩnh vực ngày, chẳng hạn như một tháng thứ 13, một ngày thứ 32 của tháng (hoặc một ngày 29 tháng hai vào năm không nhuận), một ngày 367 của năm, vv tràn có chứa các chỉ số của đơn vị không hợp lệ để phù hợp với #invalidAt (xem bên dưới); -1 nghĩa là không tràn.
  • invalidMonth: Tên tháng không hợp lệ, chẳng hạn như thời điểm ('Marbruary', 'MMMM') ;. Chứa chuỗi tháng không hợp lệ hoặc không có giá trị null.
  • empty: Chuỗi đầu vào không chứa gì có thể phân tích cú pháp, chẳng hạn như thời điểm ('điều này là vô nghĩa') ;. Boolean.
  • Vv

Nguồn: http://momentjs.com/docs/


35
2017-10-14 20:18



Giải pháp tốt nhất, cực kỳ dễ thực hiện, hoạt động với bất kỳ định dạng nào (trường hợp của tôi là dd / MM / yyyy), cũng biết năm nhuận và không chuyển đổi ngày không hợp lệ (ví dụ: 29/02/2015) thành các định dạng hợp lệ (ví dụ: 30/03/2015). Để kiểm tra một ngày trong formad dd / MM / yyyy tôi đã phải sử dụng moment("11/06/1986", "DD/MM/YYYY").isValid(); - Rafael Merlin
Việc sử dụng Moment này đã không được chấp nhận :( - James Sumners
@JamesSumners cách / tại sao? - binki
Việc sử dụng này đã không được khấu hao. Thời gian gọi (đầu vào) mà không có chuỗi định dạng bị khấu hao (trừ khi đầu vào được định dạng ISO). - Chet
Phương pháp này có thể rất chậm khi xử lý nhiều ngày. Tốt hơn nên sử dụng regex trong những trường hợp đó. - Grid Trekkor


Có muốn đề cập đến tiện ích con jQuery UI DatePicker có phương thức tiện ích xác thực ngày rất tốt để kiểm tra định dạng và tính hợp lệ (ví dụ: không cho phép ngày 01/33/2013).

Ngay cả khi bạn không muốn sử dụng tiện ích con ngày tháng trên trang của mình làm phần tử giao diện người dùng, bạn luôn có thể thêm thư viện .js vào trang của mình và sau đó gọi phương thức trình xác thực, chuyển giá trị bạn muốn xác thực vào đó. Để làm cho cuộc sống trở nên dễ dàng hơn, nó lấy một chuỗi làm đầu vào chứ không phải đối tượng Ngày tháng JavaScript.

Xem: http://api.jqueryui.com/datepicker/

Nó không được liệt kê như một phương thức, nhưng nó ở đó - như một hàm tiện ích. Tìm kiếm trang "phân tích cú pháp" và bạn sẽ tìm thấy:

$ .datepicker.parseDate (định dạng, giá trị, cài đặt) - Trích xuất một ngày từ một giá trị chuỗi với một định dạng được chỉ định.

Sử dụng ví dụ:

var stringval = '01/03/2012';
var testdate;

try {
  testdate = $.datepicker.parseDate('mm/dd/yy', stringval);
             // Notice 'yy' indicates a 4-digit year value
} catch (e)
{
 alert(stringval + ' is not valid.  Format must be MM/DD/YYYY ' +
       'and the date value must be valid for the calendar.';
}

(Tìm thêm thông tin về định dạng ngày tháng được tìm thấy tại http://api.jqueryui.com/datepicker/#utility-parseDate)

Trong ví dụ trên, bạn sẽ không thấy thông báo cảnh báo kể từ '01 / 03/2012 'là ngày hợp lệ theo lịch theo định dạng được chỉ định. Tuy nhiên, nếu bạn đã thực hiện 'stringval' bằng '13 / 04/2013 ', ví dụ: bạn sẽ nhận được thông báo cảnh báo vì giá trị '13 / 04/2013' không có giá trị lịch.

Nếu một giá trị chuỗi được truyền vào được phân tích cú pháp thành công, giá trị của 'testdate' sẽ là một đối tượng Date Javascript biểu diễn giá trị chuỗi được truyền vào. Nếu không, nó sẽ không được xác định.


35
2018-02-15 19:30



Upvote cho là câu trả lời đầu tiên làm việc với các định dạng ngày không phải tiếng anh / miền địa phương. - ax.