16 điểm bởi GN⁺ 2024-08-25 | 5 bình luận | Chia sẻ qua WhatsApp
  • Một trong những thay đổi đáng chú ý nhất gần đây của ECMAScript là đề xuất Temporal
    • API này đã có thể sử dụng ngay thông qua polyfill do nhóm FullCalendar cung cấp
    • Một trong những ưu điểm lớn nhất của API này là cuối cùng đã có một đối tượng native để biểu diễn "Zoned Date Time"

Zoned Date Time là gì?

  • Khi xử lý ngày tháng theo cách con người sử dụng, chúng ta thường nói về ngày và giờ mà bỏ qua múi giờ
  • Tuy nhiên, đối tượng "Date" của JavaScript chỉ xử lý các con số nên ý nghĩa ban đầu của ngày tháng bị mất đi
  • Ví dụ, khi muốn ghi lại thời điểm thanh toán bằng thẻ, nhiều người có thể dùng đoạn mã như sau
    const paymentDate = new Date('2024-07-20T10:30:00');  
    
  • Trình duyệt sẽ tính mili giây dựa trên múi giờ của người dùng (CET). Nhưng thông tin đã lưu có thể được diễn giải khác nhau tùy theo múi giờ
  • Ngoài thực tế rất quan trọng là trong JavaScript, ngày tháng không dựa trên UTC mà là POSIX, nơi leap second bị bỏ qua hoàn toàn, còn có vấn đề là nếu chỉ còn lại con số thì ý nghĩa gốc của ngày tháng sẽ biến mất
  • Nhiều người nghĩ rằng chỉ cần làm việc với UTC hoặc truyền ngày tháng ở định dạng ISO là an toàn, nhưng điều đó không đúng vì vẫn có thể bị mất thông tin

UTC là chưa đủ

  • Ngay cả khi làm việc với định dạng ISO, khi hiển thị ngày tháng vẫn thiếu thông tin về múi giờ
  • Hàm chuyển timestamp thành ngày tháng mà con người có thể đọc được không phải là injective (hàm đơn ánh)
  • Ví dụ, khi bạn đi từ Madrid sang Sydney rồi quay về, vấn đề múi giờ trong lịch sử giao dịch ngân hàng có thể gây ra nhầm lẫn

Giới thiệu Temporal API

  • Temporal API giới thiệu đối tượng Temporal.ZonedDateTime để biểu diễn ngày và giờ kèm múi giờ
  • API này đề xuất một phần mở rộng của RFC 3339, đưa ra tiêu chuẩn để serialize và deserialize ngày tháng dưới dạng chuỗi
  • 1996-12-19T16:39:57-08:00[America/Los_Angeles]
    • Chuỗi này biểu thị 16 giờ 39 phút 57 giây ngày 19 tháng 12 năm 1996,
    • offset so với UTC là -08:00 (giờ chuẩn Thái Bình Dương PST, nơi Los Angeles thuộc về)
    • đồng thời chỉ định thêm múi giờ liên quan ("giờ chuẩn Thái Bình Dương") để các ứng dụng có nhận thức về múi giờ có thể cân nhắc
  • Hỗ trợ nhiều hệ lịch khác nhau (ví dụ: Phật lịch, Trung Quốc, Dangi, Gregory, Hồi giáo, Ba Tư, Nhật Bản, v.v.)

Các phép toán cơ bản

Tạo ngày tháng
  • Temporal API cung cấp công cụ mạnh mẽ để xử lý múi giờ
  • Ví dụ, khi tạo đối tượng Temporal.ZonedDateTime, múi giờ được phản ánh chính xác:
    const zonedDateTime = Temporal.ZonedDateTime.from({  year: 2024,  month: 8,  day: 16,  hour: 12,  minute: 30,  second: 0,  timeZone: 'Europe/Madrid'});  
    
  • Nhờ đó có thể giữ được thời gian chính xác ngay cả khi có thay đổi múi giờ hoặc điều chỉnh giờ địa phương như DST
So sánh ngày tháng
  • Đối tượng ZonedDateTime cung cấp phương thức compare để so sánh hai ZonedDateTime:
    const one = Temporal.ZonedDateTime.from('2020-11-01T01:45-07:00[America/Los_Angeles]');  
    const two = Temporal.ZonedDateTime.from('2020-11-01T01:15-08:00[America/Los_Angeles]');  
    Temporal.ZonedDateTime.compare(one, two);  // => -1  
    
Các tính năng tích hợp hữu ích
  • Thuộc tính hoursInDay trả về số giờ thực tế của ngày đó:
    Temporal.ZonedDateTime.from('2020-03-08T12:00-07:00[America/Los_Angeles]').hoursInDay;  // => 23  (ngày bắt đầu DST)  
    
Chuyển đổi múi giờ
  • Có thể thay đổi múi giờ của ZonedDateTime bằng phương thức withTimeZone:
    zdt = Temporal.ZonedDateTime.from('1995-12-07T03:24:30+09:00[Asia/Tokyo]');  
    zdt.withTimeZone('Africa/Accra').toString(); // => '1995-12-06T18:24:30+00:00[Africa/Accra]'  
    
Phép toán số học cơ bản
  • Có thể dùng phương thức .add để cộng hoặc trừ ngày theo quy tắc DST:
    zdt = Temporal.ZonedDateTime.from('2020-03-08T00:00-08:00[America/Los_Angeles]');  
    laterDay = zdt.add({ days: 1 });  // => 2020-03-09T00:00:00-07:00[America/Los_Angeles]  
    
Tính chênh lệch giữa các ngày giờ
  • Phương thức .until tính khoảng chênh lệch giữa hai thời điểm và trả về đối tượng Temporal.Duration
    • Ví dụ có thể dùng như zdt.until(other)

Kết luận

  • Temporal API đang tạo ra thay đổi mang tính cách mạng trong cách JavaScript xử lý thời gian
  • Bài viết này đã đề cập đến sự khác biệt giữa ngày tháng con người đọc được và ngày tháng UTC, cũng như cách biểu diễn chúng chính xác bằng đối tượng Temporal.ZonedDateTime
  • Trong bài tiếp theo, tác giả sẽ khám phá những đối tượng thú vị khác như Instant, PlainDate và Duration

Ý kiến của GN⁺

  • Vấn đề xử lý ngày giờ vốn gây khó khăn cho các lập trình viên JavaScript trong thời gian dài có thể sẽ được giải quyết nhờ Temporal API
  • API này có thể tự động xử lý các vấn đề về múi giờ và DST, nên rất hữu ích khi phát triển ứng dụng toàn cầu
  • Khả năng tương thích với đối tượng Date hiện có và các vấn đề migration vẫn là những điểm cần cân nhắc
  • Temporal API được thiết kế theo hướng rõ ràng, trực quan và còn hỗ trợ nhiều hệ lịch khác nhau, nên cũng rất mạnh về mặt quốc tế hóa
  • Kỳ vọng rằng thay đổi này sẽ cải thiện đáng kể năng suất của lập trình viên JavaScript

5 bình luận

 
kyc1682 2024-08-26

Cuối cùng cũng tới!

 
hongminhee 2024-08-26
 
huiya 2024-08-26

Quá đã, khi thiết kế dịch vụ toàn cầu thì chuyện ngày tháng lúc nào cũng làm đau đầu.
Cái này mình rất muốn thử một lần.

 
jjpark78 2024-08-26

Thật sự, cuối cùng cũng đến lúc không cần dùng moment hay dayjs nữa sao?

 
GN⁺ 2024-08-25
Ý kiến Hacker News
  • Việc xử lý ngày và giờ trong Javascript rất khó

    • Thư viện Moment nhầm lẫn giữa ngày và thời gian, gây ra nhiều vấn đề
    • Thư viện Arrow của Python cũng mắc cùng sai lầm
    • Thư viện Chrono của Rust có tính dự đoán cao và ít lỗi hơn
    • Date và Moment của JS rất khó sử dụng
  • API mới được kỳ vọng sẽ giải quyết vấn đề múi giờ của JS

    • Có vấn đề là ở một số trường hợp thì phân tích múi giờ thành công, nhưng ở các trường hợp khác lại giả định là UTC
    • Tôi đã gặp rất nhiều khó khăn vì vấn đề này ở công ty cũ
  • Hàm chuyển đổi timestamp thành ngày tháng con người có thể đọc được không phải là đơn ánh

    • Có sự nhầm lẫn giữa các khái niệm tính đơn ánh và tính xác định tốt
    • Với timestamp t, không tồn tại một ngày tháng dạng con người có thể đọc được duy nhất x
  • Một câu đùa về đường cong độ khó của việc xử lý thời gian

    • Người mới bắt đầu chỉ dùng timestamp UTC
    • Người ở mức trung cấp khẳng định rằng cần lưu và chuyển đổi múi giờ
    • Cao thủ thì lại quay về chỉ dùng timestamp UTC
  • Nếu dùng nhiều ví dụ về ngày trong tương lai hơn thì bài viết sẽ thuyết phục hơn

    • Khi ghi lại timestamp, chỉ cần UTC và vị trí là đủ
    • Ví dụ về ngân hàng chỉ là vấn đề UX, không phải mất mát thông tin
  • Người dùng cảm thấy bất an vì không hiểu cách xử lý thời gian

    • Yêu cầu giới thiệu một tài liệu nhập môn tốt để hiểu các vấn đề xử lý thời gian trong những ngôn ngữ như Python
  • Có một tiêu chuẩn datetime tốt mới chỉ là một nửa cuộc chiến

    • Nửa còn lại là được chấp nhận rộng rãi
    • Để tương thích với các hệ thống khác, chuyển sang chuỗi ISO hoặc unix timestamp là an toàn
  • Chuỗi ngày ISO cần nắm bắt chính xác thông tin

    • Có nghi ngờ về ý tưởng rằng JavaScript hay các ngôn ngữ khác cần một cấu trúc tích hợp sẵn
    • Temporal và Date giải quyết những vấn đề đơn giản theo cách phức tạp
  • Câu hỏi về cách xử lý vấn đề này trong Postgres

  • Thiếu bằng chứng cho thấy Temporal sẽ thực sự được triển khai

    • Cũng như nhiều đề xuất JS đầy hứa hẹn khác, nó chỉ được thảo luận trong thời gian dài