Bạn có thể đã nghe rằng API ngày và giờ của PHP hơi lộn xộn và thực sự mọi thứ đều không hoàn hảo, nhưng đó không phải là lý do để khiến code và logic ứng dụng của bạn trở nên lộn xộn. PHP vẫn đủ mạnh để bất kỳ ứng dụng nào xử lý ngày và giờ theo cách tiêu chuẩn, dễ dàng duy trì và có được hành vi mà bạn thực sự mong đợi (không có gì ngạc nhiên với múi giờ của người dùng ngoại lai, thời gian mùa hè tràn 30/31 tháng, năm nhuận, v.v.). ).

Sử dụng các cài đặt phù hợp

Đầu tiên, đặt múi giờ mặc định thành UTC.

Bạn cũng có thể thay đổi cài đặt này từ php.ini bằng mục nhập date.timezone. Nếu bạn sử dụng một framework, sẽ có một cấu hình chuyên dụng (trong Laravel, đó là thuộc tính 'timezone' trong config/ app.php. Nhưng có một điều chắc chắn là bạn phải thiết lập nó, bạn không nên làm việc với một múi giờ không xác định và cho một khả năng tương thích tốt hơn của ứng dụng của bạn trên bất kỳ máy chủ/ lưu trữ nào, cài đặt ứng dụng ở cấp ứng dụng là an toàn hơn).

Lười biếng và giữ gìn dữ liệu

Như thường lệ trong lập trình, bạn nên đợi giây phút cuối cùng để chuyển đổi dữ liệu, thay vì thực hiện tất cả công việc ngay từ đầu. Về ngày tháng, bạn nên hoãn các chuyển đổi (định dạng, chuyển đổi, bản dịch, v.v.) dữ liệu ngày và giờ miễn là bạn có thể.

Giải pháp A: Gửi bản thô cho khách hàng

Trong trường hợp tốt nhất, bạn sẽ hoàn toàn không xử lý nó từ máy chủ của mình và để một số người dùng front-end xử lý nó, ví dụ: sử dụng momentjs hoặc đơn giản là đối tượng Date gốc trong JavaScript.

Giả sử bạn nhận được ngày-giờ như '2018–05–12 23: 16: 46.123456' từ DB của mình hoặc bất kỳ thông tin đầu vào nào (có thể có hoặc không có mili giây/ micro giây, ngày và giờ có thể được phân tách bằng dấu cách hoặc chữ “T” và nó có thể được gắn với múi giờ nhưng như đã nói sớm hơn, bạn chỉ cần có UTC trong DB của mình và làm múi giờ mặc định trong PHP), sau đó bạn có thể xuất chuỗi JS cần với như sau:

Bạn sẽ nhận được ‘2018–05–12T23: 16: 46.123456Z’, điều này có thể được chuyển cho lớp Date JS gốc:

Khi tạo đối tượng Date, trình duyệt/ front-end người dùng sẽ tự động chuyển ngày và giờ từ UTC (vì “Z” có nghĩa là UTC) sang múi giờ địa phương.

Sau đó, .toLocaleString sẽ định dạng nó bằng cách sử dụng cài đặt máy khách (quốc gia/ khu vực).

Ghi chú nhanh về DateTimeImmutable. PHP cung cấp cả DateTime và DateTimeImmutable, vì vậy bạn có thể quyết định xem đối tượng ngày của mình có thể thay đổi được hay không. Ngày tháng cố định thường an toàn hơn vì thay vì sửa đổi đối tượng hiện tại, bất kỳ phương pháp sửa đổi nào sẽ tạo ra một đối tượng mới nên vẫn có thể sử dụng đối tượng mới và đối tượng gốc, như trong ví dụ này:

 

Giải pháp B: Định dạng nó bằng PHP

Vì nhiều lý do, bạn có thể không áp dụng giải pháp A. Đầu tiên là nếu bạn không có front-end (gửi e-mail, kết xuất CLI, v.v.)

Trong trường hợp này, bạn sẽ cần chọn múi giờ và định dạng/ ngôn ngữ hiển thị với PHP, nó có thể được đọc từ cài đặt trình duyệt, được người dùng chọn theo cách thủ công thông qua biểu mẫu, nhưng vì phần này không phải là chủ đề chính, nhưng chúng ta có chúng trong các biến.

Bạn có thể nghĩ rằng những cài đặt hỗn hợp Hoa Kỳ và Châu Âu là mâu thuẫn nhưng thực tế không phải vậy. Ta đã cố ý chọn chúng để làm rõ rằng bạn không thể đoán được cái này từ cái còn lại. $lang là “Người dùng muốn bạn nói chuyện với họ bằng ngôn ngữ nào?”, $timezone là “Người dùng ở đâu?” vì vậy nó trả lời các câu hỏi khác nhau.

Cụ thể, ta sẽ sử dụng $lang để dịch các từ nếu cần (Thứ Hai/ Tháng Một/ “st”) và chọn định dạng: DD/ MM/ YYYY trong fr_FR, MM/ DD/ YYYY trong en_US, DD.MM.YYYY trong en_UK , phần này chủ yếu phụ thuộc vào khu vực ngôn ngữ chứ không phụ thuộc vào khu vực bạn đang ở, nếu bạn sống ở Chicago và đi du lịch một tuần đến London, bạn có thể sẽ không thay đổi cài đặt máy tính của mình để hiển thị ngày dưới dạng DD.MM.YYYY bạn vẫn sẽ nhận được ngày hiển thị trong en_US.

Tuy nhiên, bạn sẽ nhận được thời gian theo múi giờ Châu Âu/ Luân Đôn.

Đầu tiên hãy xem cách xử lý nó với vanilla PHP:

Thật ra, nội dung ngày và giờ không phải là điểm mạnh của PHP. Bạn có thể làm tốt hơn một chút bằng cách cài đặt phần mở rộng intl và sử dụng lớp IntlDateFormatter (http://php.net/manual/en/class.intldateformatter.php). Không thì bạn sẽ đối mặt với code kiểu rất thủ tục này.

Nó sẽ tìm kiếm ngôn ngữ và định dạng phù hợp (%x là định dạng ngày ưa thích và %X là định dạng thời gian ưa thích) trong các gói ngôn ngữ được cài đặt trên máy, sau đó nó hiển thị với múi giờ phù hợp.

Nhưng có một điểm yếu: ở đây ta thử en_US.UTF-8, en_US.utf8, en_US rồi cuối cùng là en vì tên ngôn ngữ phụ thuộc vào gói cài đặt (hỗ trợ OS/ utf8) và mỗi máy có thể có sẵn nhiều ngôn ngữ khác nhau. Vì vậy, chúng tôi không chắc mình sẽ nhận được ngôn ngữ chính xác nào và ngay cả khi có ngôn ngữ nào có trong số đó hay không.

Đã có Carbon

Để có được một bản quốc tế hóa đáng tin cậy, bạn sẽ cần phải nhúng các bản dịch vào mọi ngôn ngữ mà bạn muốn hỗ trợ và để có được ngay trong đối tượng ngày tháng mà bạn sẽ cần để mở rộng lớp DateTime (Immutable). Rất may, bạn không cần phải bắt đầu lại mọi thứ, có những thư viện nhúng bản dịch và định dạng để có thể xử lý hầu hết các nhu cầu về ngày tháng. Ta sẽ lấy Carbon, được sử dụng rộng rãi, có sẵn trong Laravel. Ngày tháng mà bạn nhận được từ các mô hình của mình thực sự là các mẫu của Carbon. Ngoài ra, bạn có thể dễ dàng cài đặt nó với trình soạn (https://getcomposer.org/).

Tham khảo tài liệu để cài đặt hoặc nâng cấp lên phiên bản mới nhất: https://carbon.nesbot.com/

Nếu bạn có phiên bản Laravel <5.8, bạn đang sử dụng phiên bản Carbon 1 theo mặc định, nhưng bạn có thể tìm thấy trong trang chính của tài liệu hướng dẫn cách làm cho Carbon 2 hoạt động với phiên bản Laravel của bạn.

Bây giờ, giả sử bạn có Carbon 2.10 trở lên, bạn có thể sử dụng cả hai lớp \Carbon\Carbon và \Carbon\CarbonImmutable cho cả DateTime và DateTimeImmutable tương ứng. Như bất kỳ tên lớp PHP nào có không gian tên, bạn có thể sử dụng Carbon\Carbon; và / hoặc sử dụng Carbon\CarbonImmutable; ở đầu tệp và sau đó chỉ cần gọi Carbon và CarbonImmutable sau trong tệp của bạn.

Xử lý carbon chuỗi JSON để ví dụ đầu tiên của ta trở thành:

Và ví dụ json_encode với nhiều ngày tháng trong đó đơn giản trở thành:

Sau đó, bây giờ đến quốc tế hóa và múi giờ, ta sẽ dựa vào bản dịch Carbon nội bộ (xem tất cả các ngôn ngữ có sẵn tại đây: https://carbon.nesbot.com/docs/#api-localization):

Bạn có nhiều cách nhưng calender là một cách rất thân thiện với người dùng để hiển thị ngày và giờ, nếu thời gian là ngày hiện tại, bạn sẽ nhận được “Hôm nay lúc 3:54 chiều”, nếu đó là tuần hiện tại và trong quá khứ “Thứ Hai lúc 11:30 sáng”, nếu xa hơn, chỉ cần “01/01/2022” và tất cả các từ và định dạng sẽ khớp với biến $lang.

Sau đó, nếu bạn có giao diện người dùng JS, bạn có thể hiển thị nó theo cách tương tự nhờ vào moment.js (https://momentjs.com/):

Vì vậy, bạn nhận được cùng một hiển thị ngày của bạn trong mọi đầu ra.

Từ phía PHP, bạn vẫn có thể rút ngắn mọi thứ một chút bằng cách sử dụng macro().

Trong mọi trường hợp, bạn nhận được nó với $timezone và $lang. Trong ví dụ này, ta giả sử các biến đó đã được đặt, nếu chúng có thể là giá trị rỗng, bạn phải cung cấp giá trị dự phòng, ví dụ:

Muốn mặt trước giống nhau? Moment.js cũng có thể làm điều đó:

Đầu vào của người dùng có gì?

Giờ ta đã biết cách gửi và hiển thị ngày tháng từ máy chủ đến máy khách, hãy bàn về việc gửi ngày và giờ từ máy khách đến máy chủ.

Bạn có thể hỏi ngày bằng nhiều công cụ biểu mẫu (nhập văn bản miễn phí, bộ chọn năm-tháng-ngày) hoặc sử dụng đầu vào HTML5 (type = ”date” và type = ”time”) được hỗ trợ bởi các trình duyệt thực bị thiếu trong Internet Explorer, Safari và Opera Mini. Bạn cũng có thể trả google công cụ chọn ngày (+ bất kỳ thư viện nào bạn sử dụng nếu có) và tìm thấy rất nhiều bộ chọn siêu vừa ý.

Vì vậy, tùy thuộc vào công cụ của bạn, bạn có thể truy xuất số, chuỗi hoặc đối tượng Ngày. Trước tiên, các chuỗi và số không thích hợp để được gửi thô đến máy chủ. Khi người dùng nhập ngày và giờ, nghĩa là anh ta (ngay cả khi anh ta không nhận ra) đang nhập ngày giờ này trong múi giờ của chính mình. Vì vậy, máy chủ sẽ phải giải thích các chuỗi và số đó bằng cách sử dụng múi giờ của người dùng mà anh ta sẽ phải đoán/ hỏi/ phát hiện. Đừng làm vậy. Chỉ cần nói với máy chủ của bạn bằng ngôn ngữ thời gian chung (UTC). Vì vậy, từ front-end của bạn, lấy các đầu vào đó và chuyển đổi chúng thành đối tượng Date. Giống như ta đã làm trước đó nhưng lần này sẽ không chỉ định múi giờ (không có chữ Z ở cuối) để trình duyệt tạo ra những gì ta cần chính là Date địa phương (với múi giờ hiện tại của thiết bị).

Bây giờ chúng ta có Date địa phương, bạn chỉ cần lấy chuỗi ISO từ nó với date.toISOString(). Lấy dữ liệu ở trên (2018–01–25 12:30), nó sẽ cung cấp cho bạn “2018–01–25T04: 30: 00.000Z” nếu bạn ở Chicago, “2018–01–25T11: 30: 00.000Z” nếu bạn đang ở Paris, v.v. Và đó là điều ta muốn, ta cần quan tâm đến múi giờ của người dùng. Lưu ý rằng toISOString cũng tồn tại vào thời điểm hiện tại, vì vậy bạn sẽ nhận được cùng một kết quả bằng cách sử dụng moment thay vì new Date.

Đầu ra chuỗi đó chỉ cần được gửi đến PHP (vẫn sử dụng UTC làm múi giờ nhập mặc định) và nếu bạn muốn lưu nó ở đâu đó (giả sử là cơ sở dữ liệu), bạn có thể chỉ cần sử dụng định dạng:

Xóa .u nếu bạn không cần lưu trữ mili/ micro giây. Sau đó, bạn chuẩn bị sẵn chuỗi của mình để được lưu trữ trong cột SQL DATETIME. Bạn có thể sử dụng Carbon hoặc CarbonImmutable thay vì DateTimeImmutable vì phương pháp định dạng giống nhau.

Trường hợp đặc biệt

Một lưu ý nhỏ về một số trường hợp ngoại lệ.

Đôi khi bạn muốn người dùng chỉ chọn một ngày (năm, tháng, ngày) nhưng không chọn giờ/ phút. Trong trường hợp này, bạn phải rõ ràng về ý nghĩa của ngày này. Ví dụ: nếu bạn chọn 2018–01–24 là ngày nghỉ trong lịch của mình, nghĩa là bạn sẽ không ở văn phòng cả ngày (từ 00:00:00 đến 23:59:59, múi giờ văn phòng), như thường ngày, ý nói đến cả ngày trong một múi giờ nhất định (thường là múi giờ của trình duyệt). Nếu văn phòng của bạn ở San Fransisco, đối với ai đó ở Sidney, anh ta sẽ không thể gọi cho bạn từ 2018–01–24 19:00:00 đến 2018–01–25 18:59:59, nếu bạn thêm giờ mở cửa, bạn có thể thấy rằng đối với một đồng nghiệp ở xa ở Sidney, bạn có thể liên hệ trong ngày 24 nhưng không phải ngày 25, đối với một người ở Paris, bạn sẽ ở đó vào buổi sáng nhưng không phải buổi chiều. Vì vậy, chỉ một ngày trong múi giờ của bạn là khoảng giữa 2 thời điểm đối với phần còn lại của thế giới. Đề xuất cho bạn trong trường hợp này là lưu đầu phạm vi này 2018–01–24 00:00 ở San Fransisco, vì vậy bạn tiết kiệm 2018–01–24 09:00 (UTC) trong DB của bạn. Sau đó, bạn có thể dễ dàng truy xuất thời điểm này và thêm 1 ngày (sử dụng -> modify (‘1 day’) trong PHP) để nhận được phần cuối của phạm vi, sau đó sử dụng múi giờ của người dùng để hiển thị phạm vi này theo cách họ có thể hiểu được.

Trong trường hợp khác, bạn chọn một ngày chỉ vì thời gian đã được biết trước (như chọn ngày ăn trưa), bạn có thể chỉ cần giả sử thời gian là 12:00 (giờ địa phương) và thêm nó để nhận toàn bộ chuỗi ngày-giờ của bạn .

Đôi khi người dùng phải chọn một ngày không nằm trong múi giờ của chính mình. Nếu bạn muốn đặt một khách sạn ở Tokyo, bạn sẽ chọn ngày đến (và/ hoặc thời gian) của mình bằng múi giờ Tokyo. Trong trường hợp này, bạn có thể "xóa" múi giờ của người dùng khi tạo đối tượng Date:

Vì vậy, khi bạn gọi toISOString(), về cơ bản bạn sẽ nhận được chính xác như một phương thức khởi tạo ngày.

Sau đó, bạn có thể cắt múi giờ này và buộc một múi giờ khác ở phía máy chủ:

Tất nhiên, bạn cũng sẽ phải hiển thị ngày này với múi giờ Tokyo (nó có thể được xác định rõ ràng với một đề cập như “giờ Tokyo”).

Trường hợp cuối cùng: múi giờ không xác định. Sẽ rất hiếm khi xảy ra, hầu hết khi bạn nghĩ rằng mình đang ở trong trường hợp này, nhưng trên thực tế, bạn có thể tìm thấy múi giờ bằng một số phân tích kinh doanh. Nhưng ngày sinh là một ví dụ điển hình. Nếu bạn sinh năm 1970–01–01 01:23 ở Rome, khi bạn của bạn ở New York, bạn nên nói “Tôi sinh năm 1969–12–31 19:23” hoặc bạn nên nói chính xác là tôi sinh ra ở Rome. Thông thường, bạn chỉ nói ngày (thực tế là ước tính 24 giờ) và bạn không nói địa điểm (một ước tính khác là 26 giờ khi múi giờ trên Trái đất đi từ -12h đến +14h) , vì vậy bạn đang đưa ra một thông tin rất không chính xác (1970–01–01 có thể từ ngày này là nửa đêm theo giờ GMT-12 đến 23:59 GMT + 14) và bất chấp sự mơ hồ kéo dài 50 giờ này, mọi người đều có thể chấp nhận ngày sinh của bạn như hiện tại và hiển thị nó khi bạn cho phép mọi người được xem. Trong trường hợp này, ta sẽ lấy giả sử đó là UTC (như trong ví dụ về khách sạn ở Tokyo), sau đó ta sẽ coi nó như cũ mà không có sự thay đổi múi giờ ở phía máy chủ và vẫn lưu nó mà không thay đổi. Cuối cùng, ta sẽ hiển thị ngày này theo múi giờ UTC.

 

Tổng hợp việc làm IT - Software trên VietnamWorks
VietnamWorks InTECH
Theo Kylekatarnls

TẠO TÀI KHOẢN MỚI: XEM FULL “1 TÁCH CODEFEE” - NHẬN SLOT TƯ VẤN CV TỪ CHUYÊN GIA - CƠ HỘI RINH VỀ VOUCHER 200K