Khách hàng của tôi, là người trong lĩnh vực bảo hiểm, yêu cầu ngày sinh của người được bảo hiểm tiềm năng. Nó được nhập vào một mẫu web bằng cách sử dụng một datepicker jQuery, kết nối với một thuộc tính mô hình bằng cách sử dụng Knockout và được gửi thông qua ajax trong JSON tới một bộ điều khiển MVC 4.Thực hiện DST trong JavaScript gây ra sự cố khi gửi đến bộ điều khiển MVC
Một số chủ hợp đồng đã nhận được tài liệu bảo hiểm của họ với ngày sinh sai. Trong quá trình tiếp theo điều tra, chúng tôi thấy rằng ngoài các lỗi nhập dữ liệu, đó là cực kỳ biên, ngày tháng sai tập trung ở hai giai đoạn sau:
- ba tuần cuối cùng của tháng Ba đến đầu tháng Tư
- cuối cùng tuần từ tháng 10 đến tuần đầu tiên của tháng 11.
Khi khách hàng của chúng tôi ở múi giờ Mỹ/Montreal, tôi ngay lập tức nghĩ về một vấn đề của DST. The DST rules changed in 2007 in this timezone.
Đọc một số bài viết và các câu hỏi về Stack Overflow khác, tôi đã học được rằng tiêu chuẩn ECMAScript 5 xác định rằng việc triển khai phải tính đến các quy tắc DST hiện tại và không cần phải tôn trọng lịch sử DST của các thay đổi. ES5 15.9.1.8 Trình duyệt duy nhất không tuân thủ đặc điểm kỹ thuật này tại thời điểm này là IE10 (chi tiết về điều này sau).
Với đặc điểm kỹ thuật này, trình duyệt sẽ báo cáo ngày như sau (thử nghiệm trong Chrome):
(new Date(2006, 9, 31, 0, 0, 0)).toISOString()
// 2006-10-31T04:00:00.000Z
(new Date(2008, 9, 31, 0, 0, 0)).toISOString()
// 2008-10-31T04:00:00.000Z
Trong khi các báo cáo nền tảng .NET ngày một cách chính xác như sau:
DateTime dt = new DateTime(2006, 10, 31, 0, 0, 0);
Console.WriteLine("{0:MM/dd/yy H:mm:ss zzz}", dt);
// 10-31-06 0:00:00 -05:00
dt = new DateTime(2008, 10, 31, 0, 0, 0);
Console.WriteLine("{0:MM/dd/yy H:mm:ss zzz}", dt);
// 10-31-08 0:00:00 -04:00
Một nguyên nhân của việc này vấn đề là nếu một người được bảo hiểm được sinh ra trong tuần cuối cùng của tháng 10 trước năm 2007, thời gian UTC sẽ được báo cáo cho bộ điều khiển MVC của tôi không chính xác, ví dụ:
ngày javascript đối tượng:
new DateTime(2006, 9, 31, 0, 0, 0);
Net phân tích dữ liệu JSON và nhận:
10-30-06 23:00:00 GMT
Trong các bài kiểm tra, tôi phát hiện ra rằng các đại diện bên trong của một đối tượng Date trong Javascript là không tương thích với của một .Net DateTime và tôi không thể cuộn trình phân tích cú pháp của riêng tôi bằng cách sử dụng biểu diễn JavaScript:
Javascript:
(new Date(2006, 9, 31, 0, 0, 0)).getTime()
// 1162267200000
Net:
DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(1162267200000);
Console.WriteLine("{0}", dt);
// 2006-10-31 04:00:00
(Điều này là sai, bởi vì nó được biểu diễn như ngày 30 tháng 10 năm 2006 lúc 23:00 theo giờ địa phương).
Đối với trường hợp sử dụng khách hàng của tôi , vì đó là phần ngày mà tôi quan tâm, tôi có thể chỉ đặt phần thời gian của đối tượng Date thành trưa, điều này sẽ bảo vệ tôi khỏi mọi trường hợp hiểu sai ngày về phần JavaScript.Thật không may, đây là bản vá Ugly và không giải quyết các tình huống tiềm ẩn khác, chẳng hạn như nếu khách hàng của tôi muốn chúng tôi triển khai chức năng yêu cầu chúng tôi có ngày và giờ chính xác của sự kiện đã xảy ra trong quá khứ.
Một cách tiếp cận khác là viết một thuật toán để phát hiện các tuần DST có khả năng có vấn đề trong bộ điều khiển của tôi và đặt thời gian chính xác nếu tôi nhận được ngày trong các tuần được đề cập. Thật không may, cho rằng tiêu chuẩn ECMAScript 6 chỉ rõ rằng lịch sử thay đổi DST phải được tôn trọng (vì vậy tất cả các trình duyệt trong tương lai phải xử lý tình huống đó một cách chính xác) và cho rằng IE10 đã hoạt động đúng cách, tôi sợ tạo ra một tình huống có vấn đề trong tương lai . Cách tiếp cận này cũng có vẻ sai, về mặt kiến trúc.
Một khía cạnh khác cần xem xét là nếu tôi phải chuyển mô hình từ máy khách đến máy chủ và sau đó quay lại máy khách, tôi sẽ cần tạo cách tạo lại đối tượng Ngày JavaScript "xấu" để chắc chắn không ảnh hưởng màn hình hiển thị ở phía máy khách của ứng dụng.
Không có giải pháp nào có vẻ chính xác và có thể mở rộng. Tôi không thể tin rằng không ai từng phải đối phó với vấn đề này trước đây.
Làm cách nào để khắc phục sự cố này vĩnh viễn và theo cách có thể áp dụng cho tất cả các dự án JavaScript/MVC khác?
EDIT # 1 - thông tin thêm vào một số không liên quan trực tiếp đến vấn đề:
Như @ mờ-johnson chỉ ra, có ít trường hợp các thông tin múi giờ nên được sử dụng. Tuy nhiên, trong trường hợp đó, ngày sinh được bảo hiểm tương ứng với múi giờ mà khách hàng của tôi đang ở. Hãy lấy ví dụ một người 17 tuổi sống ở Victoria-BC với sinh nhật của anh ấy là ngày 2 tháng 12. Nếu anh ta gửi báo giá bảo hiểm vào ngày 1 tháng 12 lúc 22:00, mặc dù anh ta vẫn 17 tuổi, báo giá bảo hiểm sẽ được chấp nhận vì anh ấy đã 18 trong múi giờ của khách hàng của tôi. Quy tắc tương tự cũng áp dụng cho việc định giá bảo hiểm. Đó là một yêu cầu pháp lý.
Chỉ cần rõ ràng, tôi đang tìm giải pháp toàn diện, có thể áp dụng cho bất kỳ dự án nào khác. Vấn đề cụ thể là: Javascript, chỉ trong vài tuần cụ thể trong nhiều năm trước năm 2007, báo cáo thời gian có chênh lệch 1 giờ. Sự bù đắp này luôn luôn ở đó bất kể tôi đại diện cho thời gian (múi giờ địa phương hay UTC) như thế nào, bởi vì đó là dữ liệu cơ bản (không phải là biểu diễn dữ liệu) sai.
Tôi đã sử dụng giải pháp "đặt thời gian vào buổi trưa" để tránh lỗi, nhưng vấn đề cơ bản vẫn còn. Điều gì sẽ xảy ra nếu khách hàng của tôi yêu cầu chúng tôi phát triển một ứng dụng web yêu cầu chúng tôi nhận được ngày VÀ thời gian của một sự kiện cụ thể trong quá khứ? Ví dụ: "Vui lòng nêu rõ ngày và giờ chính xác xảy ra tai nạn: ngày 31 tháng 10 năm 2005 lúc 19:32". Bộ điều khiển MVC sẽ đặt thời gian lúc 18:32.
Có thể loại bỏ hoàn toàn múi giờ khỏi phương trình không? Chỉ cần sử dụng UTC cho ngày/giờ? Nếu bạn phải theo dõi thời gian trong tương lai, hãy dịch chúng sang UTC để lưu trữ trong cơ sở dữ liệu và khi bạn cần xử lý tính toán thời gian, sau đó xử lý hiển thị giao diện người dùng trong múi giờ chính xác. –
Nhận xét hay, @StevenV. Đó là suy nghĩ đầu tiên của tôi, nhưng ngay cả ngày UTC cũng không được báo cáo chính xác trong JavaScript cho những ngày đó.Vấn đề bắt nguồn từ một sai lệch múi giờ sai trong đối tượng Date Date, vì vậy nó vẫn có mặt khi áp dụng cho biểu diễn UTC. Ngoài ra, chúng tôi phải duy trì múi giờ của khách hàng, bởi vì công ty là quốc gia và có các quy tắc kinh doanh yêu cầu chúng tôi so sánh múi giờ của người được bảo hiểm với khách hàng của tôi. – MartinVeronneau
"chúng tôi phải duy trì múi giờ của khách hàng", bạn có nghĩa là khách hàng nào? Nếu bạn đang nói về cá nhân được bảo hiểm, bạn nhận được dữ liệu đó về cá nhân như thế nào? Nếu không, bạn chỉ nhận được múi giờ của trình duyệt/hệ thống, có thể dễ dàng được sửa đổi/thay đổi. Ngoài ra, sự kỳ quặc trong (các) thử nghiệm của bạn, tham số 'month' trong hàm tạo' Date() 'là 0. Tháng 9 là ngày 8 và tháng 10 là 9. –