JavaRush /Blog Java /Random-VI /Một thư viện trực quan, mạnh mẽ để làm việc với thời gian...
theGrass
Mức độ
Саратов

Một thư viện trực quan, mạnh mẽ để làm việc với thời gian và ngày tháng cuối cùng cũng có sẵn trong Java (Phần 1).

Xuất bản trong nhóm
Java     cuối cùng cũng có một cách trực quan, đáng tin cậy để làm việc với ngày và giờ. Các nguyên tắc về ngày và giờ là nền tảng trong nhiều ứng dụng. Nhiều thứ khác nhau như ngày sinh, ngày thuê, thời gian sự kiện và giờ mở cửa cửa hàng đều dựa trên ngày và giờ, nhưng Java SE không cung cấp cách thuận tiện để làm việc với chúng. Bắt đầu với Java SE 8 , đã có một bộ gói java.time - cung cấp API có cấu trúc tốt để làm việc với ngày và giờ.
Lý lịch
    Khi Java lần đầu tiên xuất hiện, trong phiên bản 1.0 , lớp duy nhất để làm việc với ngày và giờ là java.util.Date . Điều đầu tiên các nhà phát triển nhận thấy là nó không đại diện cho “ngày tháng”. Trên thực tế, nó đại diện cho một khoảnh khắc, chính xác đến từng mili giây, được tính từ ngày 1 tháng 1 năm 1970. Tuy nhiên, dựa trên thực tế là phương thức toString() của Date hiển thị ngày và giờ theo múi giờ được chỉ định trong cài đặt java của máy , một số nhà phát triển đã kết luận nhầm rằng Date có thể hoạt động với các múi giờ. Việc sửa lớp này hóa ra khó đến mức (hoặc lười biếng đến mức trong phiên bản 1.1 chúng tôi phải thêm một lớp mới - java.util.Calendar . Thật không may, lớp Calendar hóa ra không tốt hơn Date là mấy . Dưới đây là một danh sách nhỏ các vấn đề hiện có trong quá trình triển khai:
  • Có thể thay đổi. Các lớp như ngày và giờ phải không thay đổi được.
  • Bù đắp. Năm trong Ngày bắt đầu từ năm 1900, các tháng ở cả hai lớp đều bắt đầu từ số 0.
  • Tên. Ngày thực tế không phải là "ngày" và Lịch không phải là lịch.
  • Định dạng. Định dạng chỉ hoạt động với Ngày chứ không phải Lịch và không an toàn cho chuỗi.
    Năm 2001, dự án Joda-Time được thành lập . Mục tiêu của anh ấy rất đơn giản - tạo ra một thư viện chất lượng cao để làm việc với ngày và giờ trong Java . Phải mất một thời gian nhưng phiên bản 1.0 cuối cùng đã được phát hành và nhanh chóng trở nên rất phổ biến và được sử dụng rộng rãi. Theo thời gian, các nhà phát triển ngày càng yêu cầu cung cấp một thư viện có tính tiện lợi tương tự như một phần của JDK . Với sự tham gia của Michael Nascimento Santos đến từ Brazil, dự án JSR-310 đã được khởi động , đây là quy trình chính thức để tạo và tích hợp API mới để làm việc với ngày và giờ trong JDK .
Ôn tập
API java.time mới chứa 5 gói:
  • java.time - gói cơ sở chứa các đối tượng để lưu trữ giá trị
  • java.time.chrono - cung cấp quyền truy cập vào các lịch khác nhau
  • java.time.format - định dạng và nhận dạng ngày giờ
  • java.time.temporal - thư viện cấp thấp và chức năng nâng cao
  • java.time.zone - các lớp làm việc với múi giờ
    Hầu hết các nhà phát triển sẽ chủ yếu sử dụng gói cơ sở và định dạng, và có lẽ cả java.time.temporal . Vì vậy, mặc dù 68 loại mới đã được thêm vào nhưng các nhà phát triển sẽ chỉ sử dụng khoảng một phần ba trong số đó.
ngày
    Lớp LocalDate là một trong những lớp quan trọng nhất trong API mới . Nó chứa một giá trị bất biến đại diện cho một ngày. Bạn không thể đặt thời gian hoặc múi giờ. Tên "local" có thể quen thuộc với bạn từ Joda-Time và ban đầu xuất phát từ tiêu chuẩn ISO-8601 . Nó có nghĩa chính xác là không có múi giờ. Về cơ bản, LocalDate là mô tả về một ngày, chẳng hạn như "ngày 5 tháng 4 năm 2014". Thời gian thực tế của ngày này sẽ khác nhau tùy thuộc vào múi giờ của bạn. Ví dụ: ở Úc ngày này sẽ sớm hơn 10 giờ so với ở London và sớm hơn 18 giờ so với ở San Francisco. Lớp LocalDate có tất cả các phương thức thường cần: LocalDate date = LocalDate.of(2014, Month.JUNE, 10); int year = date.getYear(); // 2014 Month month = date.getMonth(); // Июнь int dom = date.getDayOfMonth(); // 10 DayOfWeek dow = date.getDayOfWeek(); // Вторник int len = date.lengthOfMonth(); // 30 (дней в Июне) boolean leap = date.isLeapYear(); // false (не високосный год)     Trong ví dụ của chúng tôi, chúng tôi thấy một ngày được tạo bằng phương thức xuất xưởng (tất cả các hàm tạo đều là riêng tư). Tiếp theo chúng ta yêu cầu đối tượng cung cấp một số dữ liệu. Xin lưu ý rằng bảng liệt kê ThángNgày trong tuần được thiết kế để làm cho mã dễ đọc và đáng tin cậy hơn. Trong ví dụ sau chúng ta sẽ xem cách sửa đổi ngày. Vì lớp này là bất biến nên kết quả sẽ là các đối tượng mới, nhưng đối tượng ban đầu sẽ vẫn như cũ. LocalDate date = LocalDate.of(2014, Month.JUNE, 10); date = date.withYear(2015); // 2015-06-10 date = date.plusMonths(2); // 2015-08-10 date = date.minusDays(1); // 2015-08-09     Đây là những thay đổi tương đối đơn giản nhưng bạn thường cần thực hiện những sửa đổi ngày phức tạp hơn. Có một cơ chế đặc biệt cho việc này trong API java.time - TemporalAdjuster . Mục đích của nó là cung cấp một công cụ tích hợp cho phép bạn thao tác ngày tháng, ví dụ như lấy một đối tượng tương ứng với ngày cuối cùng của tháng. Một số trong số chúng được bao gồm trong API nhưng bạn có thể thêm API của riêng mình. Sử dụng công cụ sửa đổi rất dễ dàng, nhưng nó yêu cầu nhập tĩnh: import static java.time.DayOfWeek.* import static java.time.temporal.TemporalAdjusters.* LocalDate date = LocalDate.of(2014, Month.JUNE, 10); date = date.with(lastDayOfMonth()); date = date.with(nextOrSame(WEDNESDAY));     Việc sử dụng công cụ sửa đổi giúp đơn giản hóa mã của bạn rất nhiều. Không ai muốn thấy nhiều thao tác ngày tháng thủ công. Nếu một số loại thao tác ngày tháng xảy ra nhiều lần trong dự án của bạn, hãy viết công cụ sửa đổi của riêng bạn và nhóm của bạn có thể sử dụng nó như một thành phần đã được viết và thử nghiệm.
Thời gian và ngày làm giá trị
    Thật đáng để dành một chút thời gian để tìm hiểu điều gì khiến LocalDate có giá trị. Giá trị là những kiểu dữ liệu đơn giản, hoàn toàn có thể thay thế cho nhau, khi chúng bằng nhau thì việc nhận dạng các đối tượng trở nên vô nghĩa. Một ví dụ kinh điển về lớp giá trị là String . Chúng tôi so sánh các chuỗi bằng cách sử dụng Equals() và chúng tôi không quan tâm liệu các đối tượng có giống nhau hay không khi so sánh với toán tử == . Hầu hết các lớp làm việc với ngày và giờ cũng là các giá trị. Vì vậy, so sánh chúng bằng toán tử == là một ý tưởng tồi, như đã nêu trong tài liệu. Đối với những người muốn tìm hiểu thêm, hãy xem định nghĩa gần đây của tôi về VALJO , trong đó phác thảo một bộ quy tắc nghiêm ngặt mà các đối tượng có giá trị trong Java phải tuân theo , bao gồm tính bất biến, phương thức xuất xưởng và định nghĩa đúng của Equals() , hashCode , toString() , và so sánhTo .() .
Lịch thay thế
    Lớp LocalDate , giống như tất cả các lớp chính trong java.time , được liên kết với một lịch duy nhất - như được mô tả trong tiêu chuẩn ISO-8601 . Tiêu chuẩn 8601 mô tả lịch tiêu chuẩn toàn cầu, còn được gọi là lịch Gregorian. Một năm tiêu chuẩn có 365 ngày, năm nhuận - 366. Mỗi năm thứ 4 đều là năm nhuận trừ khi chia hết cho 100 hoặc chia hết cho 400. Năm trước năm đầu tiên của kỷ nguyên mới được coi là 0 để dễ tính toán. Hậu quả đầu tiên của việc đây là hệ thống mặc định là kết quả không phải lúc nào cũng khớp với kết quả được tính bằng GregorianCalendar . Lớp GregorianCalendar có một công tắc tích hợp sang hệ thống Julian cho tất cả các ngày trước ngày 15 tháng 10 năm 1582. Trong hệ thống Julian, mỗi năm thứ tư đều là năm nhuận, không có ngoại lệ. Câu hỏi đặt ra là, vì quá trình chuyển đổi từ hệ thống này sang hệ thống khác là một sự thật lịch sử, tại sao java.time không mô hình hóa nó? Có, bởi vì các quốc gia khác nhau đã chuyển sang hệ thống Gregorian vào những thời điểm khác nhau và chỉ xem xét ngày chuyển đổi của Vatican, chúng tôi sẽ nhận được dữ liệu không chính xác về hầu hết các quốc gia khác. Ví dụ, Đế quốc Anh, bao gồm cả các thuộc địa ở Bắc Mỹ, đã chuyển sang lịch Gregory vào ngày 14 tháng 9 năm 1752, gần 200 năm sau. Nga đã không thay đổi lịch của mình cho đến ngày 14 tháng 2 năm 1918 và quá trình chuyển đổi của Thụy Điển nói chung là một vấn đề u ám. Kết quả là, ý nghĩa thực tế của những ngày trước năm 1918 rất khác nhau tùy theo hoàn cảnh. Các tác giả của mã LocalDate đã đưa ra một quyết định hoàn toàn hợp lý là không mô hình hóa quá trình chuyển đổi từ lịch Julian sang lịch Gregorian, để tránh sự khác biệt. Hậu quả thứ hai của việc sử dụng ISO-8601 làm lịch mặc định trong tất cả các lớp cốt lõi là cần có một nhóm lớp bổ sung để xử lý các lịch còn lại. Giao diện Chronology là cơ sở để làm việc với các lịch thay thế, cho phép bạn tìm lịch mong muốn theo tên địa phương. Java 8 đi kèm với 4 lịch bổ sung - Phật giáo Thái Lan, Mingguo (Đài Loan), Nhật Bản và Hồi giáo. Các lịch khác có thể đi kèm với các chương trình. Mỗi lịch có một lớp ngày đặc biệt như ThaiBuddhistDate , MinguoDate , japaneseDateHijrahDate . Sẽ rất hợp lý khi sử dụng chúng trong các ứng dụng có tính bản địa hóa cao, chẳng hạn như các ứng dụng dành cho chính phủ Nhật Bản. Một giao diện bổ sung, ChronoLocalDate , được sử dụng làm bản tóm tắt cốt lõi của bốn lớp trên cùng với LocalDate, cho phép bạn viết mã độc lập với loại lịch được sử dụng. Mặc dù sự trừu tượng này tồn tại nhưng việc sử dụng nó không được khuyến khích. Hiểu lý do tại sao sự trừu tượng hóa này không được khuyến khích là điều quan trọng để hiểu cách toàn bộ API java.time hoạt động . Điểm mấu chốt là hầu hết mã được viết mà không tham chiếu đến lịch cụ thể đều không hoạt động. Ví dụ: bạn không thể chắc chắn rằng có 12 tháng trong một năm, nhưng một số nhà phát triển cộng thêm 12 tháng và cho rằng họ đã cộng cả năm. Bạn không thể chắc chắn rằng tất cả các tháng đều có cùng số ngày - trong lịch Coptic có 12 tháng có 30 ngày và 1 tháng có năm hoặc sáu ngày. Ngoài ra, bạn cũng không thể chắc chắn rằng số năm sau sẽ nhiều hơn năm hiện tại 1 đơn vị, vì trong lịch Nhật Bản, các năm được tính từ ngày tuyên bố của hoàng đế tiếp theo (trong trường hợp này thậm chí là 2 ngày cùng tháng). có thể thuộc các năm khác nhau). Cách duy nhất để viết mã chất lượng cao và hoạt động với nhiều lịch cùng một lúc là cốt lõi của mã, thực hiện tất cả các hoạt động theo ngày và giờ, phải được viết bằng lịch tiêu chuẩn và chỉ khi nhập/xuất ngày nếu nó được chuyển đổi sang các hệ thống lịch khác. Nghĩa là, bạn nên sử dụng LocalDate để lưu trữ và tất cả các thao tác ngày trong ứng dụng của mình. Và chỉ khi bản địa hóa ngày đầu vào và đầu ra, bạn mới nên sử dụng ChronoLocalDate , thường được lấy từ lớp lịch được lưu trữ trong hồ sơ người dùng. Đúng, hầu hết các ứng dụng không cần bản địa hóa nghiêm túc như vậy. Nếu bạn cần giải thích chi tiết hơn về mọi thứ được mô tả trong chương này, chào mừng bạn đến với tài liệu của lớp ChronoLocalDate .      Tiếp tục bài viết      Bài viết gốc
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION