Timezone Và Các Lưu ý Khi Chuyển đổi Thời Gian Theo Timezone Trong JS
Có thể bạn quan tâm
Khi bạn làm cho các dự án có tính chất đa quốc gia, thì việc xử lí thời gian theo múi giờ của người dùng là việc tất yếu. Ví dụ, khách hàng bên Nhật set up lịch họp lúc 9h sáng, thì ông nhân viên ở VN phải thấy thông báo “cuộc họp sẽ bắt đầu lúc 7h”, hoặc một ông sếp đang đi nghỉ mát ở Hawaii sẽ phải thấy thông báo “bạn có cuộc họp lúc 14h”.
Việc chuyển đổi thời gian hiển thị tương ứng với múi giờ bạn sẽ không cần phải quan tâm lắm, nếu dự án của bạn chỉ dừng lại ở việc tự động hiển thị thời gian dựa vào múi giờ của local, tức dựa vào múi giờ của nơi mà người dùng đang sống. Bởi đối tượng Date trong JS đã giúp chúng ta làm điều đó. Bản chất thời gian chỉ có một, nó chỉ hiển thị khác nhau ở mỗi múi giờ khác nhau mà thôi. Nhưng, nếu dự án của bạn có yêu cầu thay đổi được múi giờ theo thiết định người dùng thì sao? Tức là ông sếp đang đi du lịch Hawaii, nhưng vẫn muốn nhìn thấy chính xác ngày giờ hiển thị như thế nào như khi ông ta còn đang ngồi ở Nhật thì làm sao giờ?
Giải pháp cho việc này, đó là:
- Sẽ có một trường trong DB lưu thiết định timezone của người dùng.
- Hãy lấy thời gian theo UTC làm chuẩn. Mọi giá trị thời gian lưu trong DB hãy là thời gian theo UTC, còn hiển thị ra màn hình thì convert lại theo múi giờ được thiết định bởi người dùng.
Nhưng việc chuyển đổi múi giờ theo thiết định người dùng đó, nếu không hiểu bản chất, có thể gây chuyển đổi sai giờ, làm phát sinh bug rất khó chịu, kiểu như lệch giờ, lệch ngày, hoặc màn hình hiển thị một đằng mà lưu vào DB một nẻo. Ở bài viết này, mình sẽ vắn tắt nhưng đánh thẳng vào trọng tâm vấn đề, để các bạn nắm chắc được chuyển đổi thời gian sao cho đúng.
Chúng ta bắt đầu bằng đối tượng Date trong JS thuần trước.
new Date(date_string)nó chỉ chấp nhận “date_string” có định dạng như một trong số các định dạng sau:
“6/13/2018” (tháng/ngày/năm)“Jun 13 2018” (tháng/ngày/năm)“6/13/2018 06:27:00” (vẫn là tháng/ngày/năm, nhưng có kèm giờ/phút/giây)“6/13/2018 06:27:00 GMT-1000 (có thêm múi giờ -10)“2018-6-13T16:27:00Z” (định dạng thời gian khi lưu trong DB)
Hãy chú ý vào 2 định dạng cuối cùng. Đây đều là 2 định dạng có bao gồm thông tin về múi giờ, các định dạng kia thì không. Với định dạng kiểu timestamp lưu trong DB, bản thân chữ “Z” cho biết đây là thời gian chuẩn theo UTC, tức múi giờ 0.
Nếu giá trị khởi tạo KHÔNG CÓ TIMEZONE, Javascript sẽ tự coi đó là thời gian theo local, và lắp thêm múi giờ của local vào mà ko làm thay đổi giá trị của nó.
new Date("6/13/2018 08:27:00") // Kết quả: "Wed Jun 13 2018 08:27:00 GMT+0700"Điều này dẫn đến sai lệch giờ nếu như giá trị đầu vào của bạn theo UTC hoặc theo múi giờ khác với local. Bạn sẽ thấy nó cộng thêm một lượng so với giờ ban đầu.
Để tránh hiện tượng này, date_string của chúng ta cần phải đi kèm múi giờ.
new Date("6/13/2018 08:27:00 GMT-1000") // Kết quả: "Thu Jun 14 2018 01:27:00 GMT+0700" new Date("2018-6-13T18:27:00Z") // Kết quả: "Thu Jun 14 2018 01:27:00 GMT+0700"Thư viện moment.js :
Thư viện moment.js là một thư viện cổ điển và bị chê nhiều (thôi lí do bị chê thì các bạn search gg nhé), nhưng nó vẫn rất tốt trong chuyện chuyển đổi thời gian theo timezone.
Dự án mà mình tham gia có sử dụng thư viện này, song song với thư viện date-fns (vì bản thân date-fns ko hỗ trợ timezone). Dự án cháy quá gấp nên dường như mọi người cứ code cho nó hiện được lên màn hình là ok. Nhưng đến khi test, các lỗi lệch ngày, giờ thường xuyên xảy ra. Nhưng người fix lại không hiểu bản chất vấn đề, fix nhặng xị để cho nó đúng cho khách hàng test ko ra bug (múi giờ bên Nhật và VN chả lệch nhau là bao). Phải cho đến khi dự án bước vào giai đoạn bảo trì, mình mới dành thời gian điều tra lại code, tìm hiểu thêm trên mạng thì mới phát hiện ra lỗi tày trời này:
Giá trị thời gian đầu vào mà ko có timezone thì nó sẽ tự động ghép múi giờ local vào. Thư viện gì đi chăng nữa cũng thế thôi.
maitroisang said =))
Câu quote trên chính là tóm tắt cho toàn bộ ý chính của bài viết này. Bạn có sử dụng thư viện cao sang gì mấy mà ko truyền, hoặc ko chỉ định timezone cho nó, thì coi như vứt.
Bạn thử khởi tạo một đối tượng moment đơn giản như này:
const mmt = moment("2021-02-11 06:27:00")thì ý nghĩa của nó chả khác gì Date.
console.log(mmt.toDate()) // Kết quả: "Thu Feb 11 2021 06:27:00 GMT+0700" console.log(mnt.toISOString()) // Kết quả: "2021-02-10T23:27:00Z"Hàm toISOString() trả về thời gian theo chuẩn UTC. Như vậy nếu giá trị đầu vào của bạn là thời gian theo UTC, thì đem vào moment nó đã bị lệch rồi.
Muốn chỉ định rõ đây là thời gian theo UTC, hãy dùng moment.utc().
const mmt = moment.utc("2021-02-11 06:27:00") console.log(mmt.toDate()) // Kết quả: "Thu Feb 11 2021 13:27:00 GMT+0700" console.log(mmt.toISOString()) // Kết quả: "2021-02-11T06:27:00Z"Thế còn hàm moment.tz() là gì?
Trong trường hợp chuỗi thời gian của bạn không có timezone, bạn có thể truyền thêm timezone vào thông qua tham số thứ 2 của hàm moment.tz(). Ví dụ:
const mmt = moment.tz("2021-02-10 20:27:00", "US/Hawaii")Cơ mà, timezone phải truyền bằng chữ vậy à? Truyền bằng số có được ko?
Có. Nhưng mà bằng cách khác.
const mmt = moment.utc("2021-02-11 15:27:00").utcOffset(9) console.log(mmt.toDate()) // Kết quả: "Thu Feb 11 2021 13:27:00 GMT+0700"Lưu ý cho, đối tượng Date và hàm toDate() của moment luôn trả về giá trị date theo múi giờ của local. Trong khi màn hình luôn đòi hỏi chúng ta phải hiển thị giá trị thời gian theo thiết định timezone của người dùng. Khi đó, các bạn hãy dùng hàm format() để tách lấy phần thời gian mà bạn muốn hiển thị, sau đó vận dụng moment để chuyển đổi giá trị mà sẽ hiển thị lên màn hình. Ví dụ:
export const utcToTz = (dateString: string) => { const timezone = Storage.session.get(USER_TIMEZONE) || "Asia/Ho_Chi_Minh"; const dt = moment().utc(dateString).tz(timezone); return dt.format("YYYY-MM-DD HH:mm"); }Tổng kết lại, có 2 điều sau các bạn phải cực kì chú ý khi chuyển đổi thời gian có timezone:
- Luôn phải ý thức được rằng giá trị thời gian đầu vào của bạn theo UTC hay theo timezone, hoặc thậm chí có phải là đang theo timezone của local hay không. Từ đó chúng ta mới vận dụng hàm đúng được.
- Giá trị thời gian đầu vào của bạn có chỉ định timezone hay không, không có là phải truyền thêm đấy.
Tham khảo tại https://www.freecodecamp.org/news/the-ultimate-guide-to-javascript-date-and-moment-js/
Chia sẻ:
- X
Có liên quan
Từ khóa » Chuyển đổi Time Zone
-
Bộ Chuyển đổi Múi Giờ
-
Time Zone Converter
-
Time Zone Converter – Time Difference Calculator - Time And Date
-
Chuyển đổi Múi Giờ
-
Time Converter - The Time Now
-
Cách Thay đổi Thời Gian, Ngày, Tháng Trong Windows 10?
-
Công Thức Excel: Chuyển đổi Thời Gian Sang Múi Giờ Khác
-
Hướng Dẫn Thay đổi Timezone Trên CentOS - HOSTVN
-
Cách Thay đổi Timezone Trên Máy Chủ Linux - Knowledgebase
-
Thay đổi Múi Giờ Cho Tài Khoản Quảng Cáo - Facebook
-
Chỉnh Sửa Locale Và Timezone Settings Trong Google Sheets
-
Hướng Dẫn Thay đổi Timezone Trên CentOS - Tenten
-
Cách Chỉnh Thời Gian, Ngày, Giờ Trên Máy Tính Windows 10 Khi Bị Sai
-
Hướng Dẫn Cài đặt Timezone Và đồng Bộ Thời Gian Trên Debian 11