Date Time trong Java 8

Trong bài các bài viết trước, tôi đã Giới thiệu về kiểu Date Time trong Java. Trong bài này, chúng ta sẽ tìm hiểu thêm một số tính năng mới của Date Time trong Java 8.

1. Tại sao chúng ta cần API Date Time mới?

Trước khi tìm hiểu một số API mới, chúng ta hãy cùng nhình lại một số vấn đề về Date Time của phiên bản hiện tại:

  • Các class Java Date Time không nhất quán: chúng ta có class Date trong cả 2 package java.util và java.sql . Trong khi class formatparse chúng lại nằm ở trong package java.text.
  • java.util.Date bao gồm cả date và time trong khi java.sql.Date chỉ bao gồm date. Cả 2 class đều có cùng tên, đây là một thiết kế khá xấu.
  • Không rõ ràng trong việc định nghĩa các class cho time, timestamp, formatting và parsing. Chúng ta có lớp trừu tượng java.text.DateFormat để parse và format Date Time cần. Lớp SimpleDateFormat thường được sử dụng nhất.
  • Tất cả các class Date đều mutable,do đó chúng không an toàn khi dùng chung trong môi trường đa luồng (Multi-Thread). Đây có thể coi là 1 vấn đề lớn với các class Java Date và Calendar.
  • Class Date không cung cấp Internationalization và không hỗ trợ Timezone, sau đó các class java.util.Calendar và java.util.TimeZone được giới thiệu nhưng chúng cũng gặp phải các vấn đề bên trên.

2. Những thay đổi về Date & Time trong Java 8

API Date Time trong Java 8 cài đặt các phương thức theo chuẩn JSR-310. Nó được thiết kế để khắc phục tất cả các sai sót trong việc triển khai Date Time trước đó. Một số nguyên tắc thiết kế của API Date Time mới là:

  • Khả năng immutable (Immutability): Tất cả các class trong Date Time API mới đều là immutable, điều này tốt cho môi trường đa luồng (Multi-Thread).
  • Phân tách các mối quan tâm (Separation of Concerns): API mới phân chia rõ ràng giữa Date Time, hạn chế nhầm lẫn khi sử dụng. Nó định nghĩa phân biệt các class cho DateTimeDateTimeTimestampTimezone, …
  • Tính trong suốt (Clarity): Các method được định nghĩa 1 cách rõ ràng và thực thi các hành động giống nhau trong cùng 1 class. Ví dụ, để lấy thời gian hiện tại ta có method now(), các method format() và parse() đều được định nghĩa trong những class này. Tất cả các lớp đều sử dụng Factory Pattern và Strategy Pattern để xử lý tốt hơn. Một khi bạn đã sử dụng các phương thức trong một lớp bất kỳ, khi làm việc với các lớp khác sẽ không khó.
  • Các tính năng hữu ích (Utility operations): Tất cả các class trong API Date Time đi kèm với các tác vụ phổ biến như cộng, trừ, parsing, định dạng date/time…
  • Khả năng mở rộng (Extendable): API Date Time mới làm việc theo chuẩn ISO-8601 calendar, tuy nhiên chúng ta vẫn có thể sử dụng nó với các chuẩn không phải ISO.

3. Các package của API Date Time Java 8

  • java.time : đây là 1 package chính của API Date Time. Nó gồm các class: LocalDateLocalTimeLocalDateTimeInstantPeriodDuration, … Tất cả các class này đều là immutable và thread safe.
  • java.time.chrono: package gồm các generic API được định nghĩa cho các hệ thống có lịch không theo chuẩn ISO. Chúng ta có thể mở rộng class AbstractChronology để tạo Calendar riêng cho hệ thống của mình.
  • java.time.format : package này gồm các class sử dụng cho formatting và parsing.
  • java.time.temporal : package này gồm các temporal object và chúng ta có thể dùng chúng để lấy ngày cụ thể hoặc thời gian liên quan. Ví dụ, chúng ta có thể sử dụng chúng để tìm ra ngày đầu tiên hoặc ngày cuối cùng của tháng. Bạn có thể xác định các phương thức này một cách dễ dàng vì chúng luôn có định dạng withXXX().
  • java.time.zone*: package này gồm các class hỗ trợ các Time zone khác nhau.

4. Các ví dụ với API Date/Time trong Java 8

  • LocalDate : Tạo ra 1 instance của date theo tiêu chuẩn ISO 8601, không Time, không Time zone.
  • LocalTime : Tạo ra 1 instance của time theo tiêu chuẩn ISO 8601, không Date, không Time zone.
  • LocalDateTime : bao gồm cả 2 API trên, tạo ra instance chứa cả Date, Time và không có Time zone.
  • ZonedDateTime : bao gồm API LocalDateTime có Time zone.
  • Instant : hỗ trợ làm việc với timestamps, được sử dụng để ghi lại thời gian sự kiện trong ứng dụng. Nó lưu trữ dưới định dạng của unix timestamp. Ví dụ: 1970-01-01T00:00:00Z.
  • Period : hỗ trợ tính toán năm/ tháng/ ngày giữa 2 Date Time.
  • Duration : hỗ trợ tính toán chi tiết đến seconds and nanoseconds giữa 2 Date Time.
  • Year : Tạo ra 1 instance của date theo tiêu chuẩn ISO 8601, chỉ có Year.
  • YearMonth : Tạo ra 1 instance của date theo tiêu chuẩn ISO 8601, chỉ có Year và Month.
  • DayOfWeekMonth Enum : các enum thể hiện các ngày trong tuần, tháng. Hỗ trợ một số thao tác tính toán, biểu diễn ngày trong tuần, tháng.
  • ChronoUnit : được sử dụng để đo lượng/ tính toán thời gian như: năm, tháng, ngày, giờ, phút, giây. Ví dụ: YEARSMONTHSWEEKSHOURS, …
  • ChronoField : được sử dụng để truy xuất một phần phần nào đó của Date Time. Ví dụ: DAY_OF_MONTHDAY_OF_WEEKMONTH_OF_YEARYEAR, …

4.1. Sử dụng LocalDate

package com.maixuanviet.datetime;
 
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;
 
public class LocalDateExample {
 
    public static void main(String[] args) {
 
        // Current Date
        LocalDate today = LocalDate.now();
        System.out.println("Current Date = " + today);
 
        // Creating LocalDate by providing input arguments
        LocalDate firstDay_2014 = LocalDate.of(2014, Month.JANUARY, 1);
        System.out.println("Specific Date = " + firstDay_2014);
 
        // Try creating date by providing invalid inputs
        // LocalDate feb29_2014 = LocalDate.of(2014, Month.FEBRUARY, 29);
        // Exception in thread "main" java.time.DateTimeException:
        // Invalid date 'February 29' as '2014' is not a leap year
 
        // Current date in "Asia/Ho_Chi_Minh", you can get it from ZoneId javadoc
        LocalDate todayHCM = LocalDate.now(ZoneId.of("Asia/Ho_Chi_Minh"));
        System.out.println("Current Date in IST = " + todayHCM);
 
        // java.time.zone.ZoneRulesException: Unknown time-zone ID: IST
        // LocalDate todayIST = LocalDate.now(ZoneId.of("IST"));
 
        // Getting date from the base date i.e 01/01/1970
        LocalDate dateFromBase = LocalDate.ofEpochDay(365);
        System.out.println("365th day from base date = " + dateFromBase);
 
        // Obtains an instance of LocalDate from a year and day-of-year
        LocalDate hundredDay2014 = LocalDate.ofYearDay(2014, 100);
        System.out.println("100th day of 2014 = " + hundredDay2014);
    }
}

Output của chương trình trên:

Current Date = 2018-06-23
Specific Date = 2014-01-01
Current Date in IST = 2018-06-23
365th day from base date = 1971-01-01
100th day of 2014 = 2014-04-10

4.2. Sử dụng LocalTime

package com.maixuanviet.datetime;
 
import java.time.LocalTime;
import java.time.ZoneId;
 
public class LocalTimeExample {
 
    public static void main(String[] args) {
 
        // Current Time
        LocalTime time = LocalTime.now();
        System.out.println("Current Time=" + time);
 
        // Creating LocalTime by providing input arguments
        // LocalTime.of(int hour, int minute, int second, int nanoOfSecond)
        LocalTime specificTime = LocalTime.of(12, 20, 25, 40);
        System.out.println("Specific Time of Day = " + specificTime);
 
        // Try creating time by providing invalid inputs
        // LocalTime invalidTime = LocalTime.of(25,20);
        // Exception in thread "main" java.time.DateTimeException:
        // Invalid value for HourOfDay (valid values 0 - 23): 25
 
        // Current date in "Asia/Ho_Chi_Minh", you can get it from ZoneId javadoc
        LocalTime timeHCM = LocalTime.now(ZoneId.of("Asia/Ho_Chi_Minh"));
        System.out.println("Current Time in IST = " + timeHCM);
 
        // java.time.zone.ZoneRulesException: Unknown time-zone ID: IST
        // LocalTime todayIST = LocalTime.now(ZoneId.of("IST"));
 
        // Getting date from the base date i.e 01/01/1970
        LocalTime specificSecondTime = LocalTime.ofSecondOfDay(10000);
        System.out.println("10000th second time = " + specificSecondTime);
 
    }
}

Output của chương trình trên:

Current Time=19:56:50.479
Specific Time of Day = 12:20:25.000000040
Current Time in IST = 19:56:50.558
10000th second time = 02:46:40

4.3. Sử dụng LocalDateTime

package com.maixuanviet.datetime;
 
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZoneOffset;
 
public class LocalDateTimeExample {
 
    public static void main(String[] args) {
 
        // Current Date
        LocalDateTime today = LocalDateTime.now();
        System.out.println("Current DateTime = " + today);
 
        // Current Date using LocalDate and LocalTime
        today = LocalDateTime.of(LocalDate.now(), LocalTime.now());
        System.out.println("Current DateTime = " + today);
 
        // Creating LocalDateTime by providing input arguments
        // LocalDateTime.of(int year, Month month, int dayOfMonth, int hour, int minute, int second)
        LocalDateTime specificDate = LocalDateTime.of(2014, Month.JANUARY, 1, 10, 10, 30);
        System.out.println("Specific Date = " + specificDate);
 
        // Try creating date by providing invalid inputs
        // LocalDateTime feb29_2014 = LocalDateTime.of(2014, Month.FEBRUARY, 28, 25,1,1);
        // Exception in thread "main" java.time.DateTimeException:
        // Invalid value for HourOfDay (valid values 0 - 23): 25
 
        // Current date in "Asia/Ho_Chi_Minh", you can get it from ZoneId javadoc
        LocalDateTime todayHCM = LocalDateTime.now(ZoneId.of("Asia/Ho_Chi_Minh"));
        System.out.println("Current Date in IST = " + todayHCM);
 
        // java.time.zone.ZoneRulesException: Unknown time-zone ID: IST
        // LocalDateTime todayIST = LocalDateTime.now(ZoneId.of("IST"));
 
        // Getting date from the base date i.e 01/01/1970
        LocalDateTime dateFromBase = LocalDateTime.ofEpochSecond(10000, 0, ZoneOffset.UTC);
        System.out.println("10000th second time from 01/01/1970 = " + dateFromBase);
 
    }
 
}

Output của chương trình trên:

Current DateTime = 2018-06-23T18:05:28.574
Current DateTime = 2018-06-23T18:05:28.575
Specific Date = 2014-01-01T10:10:30
Current Date in IST = 2018-06-23T18:05:28.655
10000th second time from 01/01/1970 = 1970-01-01T02:46:40

4.4. Sử dụng ZonedDateTime

package com.maixuanviet.datetime;
 
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Set;
 
public class ZonedDateTimeExample {
 
    public static void main(String[] args) {
 
        // Get all available zones
        Set<String> allZoneIds = ZoneId.getAvailableZoneIds();
        System.out.println("allZoneIds = " + allZoneIds);
         
        ZoneId zoneHCM = ZoneId.of("Asia/Ho_Chi_Minh");
 
        // Creating LocalDateTime by providing input arguments
        LocalDateTime today = LocalDateTime.now();
        System.out.println("LocalDateTime = " + today);
 
        // Creating ZonedDateTime by providing input arguments
        ZonedDateTime hcmDateTime = ZonedDateTime.of(today, zoneHCM);
        System.out.println("ZonedDateTime = " + hcmDateTime);
         
        // using offsets
        ZoneOffset offset = ZoneOffset.of("+05:00");
        System.out.println("offset = " + offset);
         
        OffsetDateTime todayPlusFive = OffsetDateTime.of(today, offset);
        System.out.println("todayPlusFive = " + todayPlusFive);
 
        OffsetDateTime todayMinusTwo = todayPlusFive.withOffsetSameInstant(ZoneOffset.ofHours(-2));
        System.out.println("todayMinusTwo = " + todayMinusTwo);
    }
}

Output của chương trình trên:

allZoneIds = [Asia/Aden, America/Cuiaba, Etc/GMT+9, ..., Europe/Monaco]
LocalDateTime = 2018-06-23T18:15:31.015
ZonedDateTime = 2018-06-23T18:15:31.015+07:00[Asia/Ho_Chi_Minh]
offset = +05:00
todayPlusFive = 2018-06-23T18:15:31.015+05:00
todayMinusTwo = 2018-06-23T11:15:31.015-02:00

4.5. Sử dụng Instant

package com.maixuanviet.datetime;
 
import java.time.Duration;
import java.time.Instant;
 
public class InstantExample {
 
    public static void main(String[] args) {
 
        // Current timestamp
        Instant now = Instant.now();
        System.out.println("Current Timestamp = " + now);
 
        // Instant from timestamp
        Instant specificTime = Instant.ofEpochMilli(now.toEpochMilli());
        System.out.println("Specific Time = " + specificTime);
 
        // Obtain an instance of Instant from a text string
        Instant specifyString = Instant.parse("2018-06-20T10:37:30.00Z");
        System.out.println("specifyString = " + specifyString);
         
        // Obtains a Duration representing a number of standard 24 hour days
        // return Duration with format of days*24
        Duration thirtyDay = Duration.ofDays(30);
        System.out.println(thirtyDay);
 
        // Copy of this instant with the specified amount subtracted
        Instant minus5 = now.minus(Duration.ofDays(5));
        System.out.println("minus5 = " + minus5);
 
        // Copy of this instant with the specified amount added
        Instant plus5 = now.plus(Duration.ofDays(5));
        System.out.println("plus5 = " + plus5);
    }
}

Output của chương trình trên:

Current Timestamp = 2018-06-23T11:32:43.131Z
Specific Time = 2018-06-23T11:32:43.131Z
specifyString = 2018-06-20T10:37:30Z
PT720H
minus5 = 2018-06-18T11:32:43.131Z
plus5 = 2018-06-28T11:32:43.131Z

4.6. Sử dụng Period

package com.maixuanviet.datetime;
 
import java.time.LocalDate;
import java.time.Period;
 
public class PeriodExample {
 
    public static void main(String[] args) {
 
        LocalDate firstDate = LocalDate.now();
        LocalDate secondDate = LocalDate.of(2017, 5, 20);
        System.out.println("firstDate: " + firstDate); // 2018-06-23
        System.out.println("secondDate: " + secondDate); // 2017-05-20
 
        Period period = Period.between(firstDate, secondDate);
        System.out.println("period: " + period); // P-1M-3D
 
        int days = period.getDays();
        int months = period.getMonths();
        int years = period.getYears();
        boolean isNegative = period.isNegative();
        System.out.println("days: " + days); // -3
        System.out.println("months: " + months); // -1
        System.out.println("years: " + years); // -1
        System.out.println("isNegative: " + isNegative); // true
 
        Period twoMonthTenDays = Period.ofMonths(2).plusDays(10);
        System.out.println("twoMonthTenDays: " + twoMonthTenDays); // P2M10D
         
        LocalDate plusDate = firstDate.plus(twoMonthTenDays);
        System.out.println("plusDate: " + plusDate); // 2018-09-02
         
        LocalDate minusDate = firstDate.minus(twoMonthTenDays);
        System.out.println("minusDate: " + minusDate); // 2018-04-13
    }
}

4.7. Sử dụng Duration

package com.maixuanviet.datetime;
 
import java.time.Duration;
import java.time.LocalDateTime;
 
public class DurationExample {
 
    public static void main(String[] args) {
 
        LocalDateTime firstDate = LocalDateTime.now();
        LocalDateTime secondDate = LocalDateTime.of(2018, 6, 20, 0, 0, 0);
        System.out.println("firstDate: " + firstDate); // 2018-06-23T21:31:28.924
        System.out.println("secondDate: " + secondDate); // 2018-06-20T00:00
 
        // Obtains a Duration representing the duration between two temporal objects
        // The temporal objects are Instant or LocalDateTime
        Duration duration = Duration.between(firstDate, secondDate);
        System.out.println("duration: " + duration); // PT-93H-31M-28.924S
 
        long days = duration.toDays();
        long hours = duration.toHours();
        long minutes = duration.toMinutes();
        long seconds = duration.getSeconds();
        long millis = duration.toMillis();
        long nanos = duration.toNanos();
        System.out.println("days: " + days); // -3
        System.out.println("hours: " + hours); // -93
        System.out.println("minutes: " + minutes); // -5611
        System.out.println("seconds: " + seconds); // -336689
        System.out.println("millis: " + millis); // -336688924
        System.out.println("nanos: " + nanos); // -336688924000000
         
        Duration twoHours = Duration.ofHours(2);
        System.out.println("twoHours: " + twoHours); // PT2H
         
        LocalDateTime plusDate = firstDate.plus(twoHours);
        System.out.println("plusDate: " + plusDate); // 2018-06-23T23:35:21.045
         
        LocalDateTime minusDate = firstDate.minus(twoHours);
        System.out.println("minusDate: " + minusDate); // 2018-06-23T19:35:21.045
    }
}

4.8. Sử dụng Year, YearMonth

package com.maixuanviet.datetime;
 
import java.time.LocalDate;
import java.time.Year;
import java.time.YearMonth;
 
public class YearMonthExample {
 
    public static void main(String[] args) {
 
        // Year Example
 
        Year currentYear = Year.now();
        System.out.println("currentYear: " + currentYear); // 2018
 
        Year specifyYear = Year.of(2016);
        System.out.println("specifyYear: " + specifyYear); // 2016
        System.out.println("isLeap : " + specifyYear.isLeap()); // true
 
        int dayOfYear = 100;
        LocalDate localDate = currentYear.atDay(dayOfYear);
        System.out.println("localDate: " + localDate); // 2018-04-10
 
        // YearMonth Example
 
        YearMonth currentYearMonth = YearMonth.now();
        System.out.println("currentYearMonth: " + currentYearMonth);
 
        YearMonth specifyYearMonth = YearMonth.of(2016, 1);
        System.out.println("specifyYearMonth: " + specifyYearMonth);
 
        int dayOfMonth = 20;
        LocalDate localDate2 = currentYearMonth.atDay(dayOfMonth);
        System.out.println("localDate2: " + localDate2); // 2018-06-20
 
        // Year -> YearMonth
 
        YearMonth ym = currentYear.atMonth(5);
        System.out.println("ym: " + ym); // 2018-05
    }
}

4.9. Sử dụng DayOfWeek, Month Enum

package com.maixuanviet.datetime;
 
import java.time.DayOfWeek;
import java.time.Month;
import java.time.format.TextStyle;
import java.util.Locale;
 
public class WeekMonthEnumExample {
 
    public static void main(String[] args) {
         
        // DayOfWeek Enum Example
        DayOfWeek monday = DayOfWeek.MONDAY;
        System.out.println(monday); // MONDAY
        System.out.println(monday.getDisplayName(TextStyle.SHORT, Locale.getDefault())); // Mon
        System.out.println(monday.getDisplayName(TextStyle.FULL, Locale.getDefault())); // Monday
        System.out.println(monday.plus(5)); // SATURDAY
        System.out.println(DayOfWeek.of(1)); // MONDAY
        System.out.println(DayOfWeek.of(7)); // SUNDAY
        System.out.println(DayOfWeek.valueOf("SUNDAY")); // SUNDAY
        System.out.println(monday.compareTo(DayOfWeek.SUNDAY)); // -6
         
        // Month Enum Example
        Month april = Month.APRIL;
        System.out.println(april); // APRIL
        System.out.println(april.getDisplayName(TextStyle.SHORT, Locale.getDefault())); // Apr
        System.out.println(april.getDisplayName(TextStyle.FULL, Locale.getDefault())); // April
        System.out.println(april.plus(3)); // JULY
        System.out.println(Month.FEBRUARY.maxLength()); // 29
        System.out.println(Month.FEBRUARY.minLength()); // 28
        System.out.println(april.firstDayOfYear(true)); // 92
        System.out.println(Month.of(1)); // JANUARY
        System.out.println(Month.of(12)); // DECEMBER
        System.out.println(Month.valueOf("FEBRUARY")); // FEBRUARY
        System.out.println(april.compareTo(Month.FEBRUARY)); // 2
    }
}

4.10. Sử dụng ChronoUnit, ChronoField Enum

package com.maixuanviet.datetime;
 
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
 
public class ChronoFieldUnitExample {
 
    public static void main(String[] args) {
 
        // ====== ChronoUnit Example ======
 
        // Get the current date
        LocalDate today = LocalDate.now();
        System.out.println("Current date: " + today);
 
        // add 1 week to the current date
        LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
        System.out.println("Next week: " + nextWeek);
 
        // add 1 week to the current date
        LocalDate previousWeek = today.minus(1, ChronoUnit.WEEKS);
        System.out.println("Previous week: " + previousWeek);
 
        // add 1 month to the current date
        LocalDate nextMonth = today.plus(1, ChronoUnit.MONTHS);
        System.out.println("Next month: " + nextMonth);
 
        // add 1 year to the current date
        LocalDate nextYear = today.plus(1, ChronoUnit.YEARS);
        System.out.println("Next year: " + nextYear);
 
        // add 10 years to the current date
        LocalDate nextDecade = today.plus(1, ChronoUnit.DECADES);
        System.out.println("Date after ten year: " + nextDecade);
 
        // ====== ChronoField Example ======
 
        LocalDateTime currentDateTime = LocalDateTime.now();
        System.out.println("\ncurrentDateTime: " +currentDateTime);
        System.out.println("Year: " + currentDateTime.get(ChronoField.YEAR));
        System.out.println("Month: " + currentDateTime.get(ChronoField.MONTH_OF_YEAR));
        System.out.println("Day of month: " + currentDateTime.get(ChronoField.DAY_OF_MONTH));
        System.out.println("Hour of day: " + currentDateTime.get(ChronoField.HOUR_OF_DAY));
        System.out.println("Minute of hour: " + currentDateTime.get(ChronoField.MINUTE_OF_HOUR));
    }
}

Output của chương trình:

Current date: 2018-06-23
Next week: 2018-06-30
Previous week: 2018-06-16
Next month: 2018-07-23
Next year: 2019-06-23
Date after ten years: 2028-06-23
 
currentDateTime: 2018-06-23T23:00:07.812
Year: 2018
Month: 6
Day of month: 23
Hour of day: 23
Minute of hour: 0

4.11. Lớp tiện ích Java 8 Date API

Như đã đề cập ở phần trên, hầu hết các lớp Date Time cung cấp các phương thức tiện ích như cộng / trừ ngày, tuần, tháng, … Một số phương thức tiện ích khác để điều chỉnh ngày sử dụng TemporalAdjuster và tính toán, so sánh khoảng thời gian giữa hai ngày.

Ví dụ bên dưới đây cho LocalDate, với LocalTimeLocalDateTime, … các bạn tìm hiểu thêm ở các link tham khảo của oracle cuối bài viết.

package com.maixuanviet.datetime;
 
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
import java.time.temporal.TemporalAdjusters;
 
public class DateApiUtilities {
 
    public static void main(String[] args) {
 
        LocalDate today = LocalDate.now();
 
        // Get the Year, check if it's leap year
        System.out.println("Year " + today.getYear() + " is Leap Year? " + today.isLeapYear());
 
        // Compare two LocalDate for before and after
        System.out.println("Today is before 01/01/2018? " + today.isBefore(LocalDate.of(2018, 1, 1)));
 
        // Create LocalDateTime from LocalDate
        System.out.println("Current Time = " + today.atTime(LocalTime.now()));
 
        // plus and minus operations
        System.out.println("10 days after today will be " + today.plusDays(10));
        System.out.println("3 weeks after today will be " + today.plusWeeks(3));
        System.out.println("20 months after today will be " + today.plusMonths(20));
 
        System.out.println("10 days before today will be " + today.minusDays(10));
        System.out.println("3 weeks before today will be " + today.minusWeeks(3));
        System.out.println("20 months before today will be " + today.minusMonths(20));
 
        // Temporal adjusters for adjusting the dates
        LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth());
        System.out.println("First date of this month= " + firstDayOfThisMonth);
         
        LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth());
        System.out.println("Last date of this month= " + lastDayOfThisMonth);
         
        LocalDate lastDayOfYear = today.with(TemporalAdjusters.lastDayOfYear());
        System.out.println("Last date of this year= " + lastDayOfYear);
 
        Period period = today.until(lastDayOfYear);
        System.out.println("Period Format= " + period);
        System.out.println("Months remaining in the year= " + period.getMonths());
    }
}

Output của chương trình trên:

Year 2018 is Leap Year? false
Today is before 01/01/2018? false
Current Time = 2018-06-23T18:49:40.865
10 days after today will be 2018-07-03
3 weeks after today will be 2018-07-14
20 months after today will be 2020-02-23
10 days before today will be 2018-06-13
3 weeks before today will be 2018-06-02
20 months before today will be 2016-10-23
First date of this month= 2018-06-01
Last date of this month= 2018-06-30
Last date of this year= 2018-12-31
Period Format= P6M8D
Months remaining in the year= 6

4.12. Định dạng (Format) và Phân tích (Parse) Date Time trong Java 8

Trong các API của LocalDate, LocalTime, LocalDateTime, … cung cấp 2 phương thức cho việc phân tích và định dạng Date Time:

  • format(pattern) : được sử dụng để định dạng một giá trị Date Time sang chuỗi tương ứng với pattern được cung cấp.
  • parse(str, pattern) : được sử dụng để phân tích chuỗi bất kỳ với pattern được cung cấp sang kiểu Date Time tương ứng.

Ví dụ:

package com.maixuanviet.datetime;
 
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
 
public class DateParseFormatExample {
 
    public static void main(String[] args) {
 
        // Format LocalDate examples
        LocalDate date = LocalDate.now();
        System.out.println("Default format of LocalDate = " + date);
        System.out.println(date.format(DateTimeFormatter.ofPattern("d::MMM::uuuu")));
        System.out.println(date.format(DateTimeFormatter.BASIC_ISO_DATE));
 
        // Format LocalDateTime examples
        LocalDateTime dateTime = LocalDateTime.now();
        System.out.println("\nDefault format of LocalDateTime = " + dateTime);
        System.out.println(dateTime.format(DateTimeFormatter.ofPattern("d::MMM::uuuu HH::mm::ss")));
        System.out.println(dateTime.format(DateTimeFormatter.BASIC_ISO_DATE));
 
        // Format Instant Example
        Instant timestamp = Instant.now();
        System.out.println("\nDefault format of Instant = " + timestamp);
 
        // Parse examples
        LocalDateTime dt = LocalDateTime.parse("27::Apr::2014 21::39::48",
                DateTimeFormatter.ofPattern("d::MMM::uuuu HH::mm::ss"));
        System.out.println("\nDefault format after parsing = " + dt);
    }
}

Output của chương trình trên:

Default format of LocalDate = 2018-06-23
23::Jun::2018
20180623
 
Default format of LocalDateTime = 2018-06-23T19:10:39.309
23::Jun::2018 19::10::39
20180623
 
Default format of Instant = 2018-06-23T12:10:39.310Z
 
Default format after parsing = 2014-04-27T21:39:48

4.13. Chuyển đổi qua lại giữa các kiểu dữ liệu Date Time

package com.maixuanviet.datetime;
 
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
 
public class DateTimeConversionExample {
 
    public static void main(String[] args) {
 
        // LocalDate/ LocalTime <-> LocalDateTime/ ZonedDateTime
        LocalDate date = LocalDate.now();
        LocalTime time = LocalTime.now();
        LocalDateTime dateTimeFromDateAndTime = LocalDateTime.of(date, time);
        LocalDate dateFromDateTime = dateTimeFromDateAndTime.toLocalDate();
        LocalTime timeFromDateTime = dateTimeFromDateAndTime.toLocalTime();
        ZonedDateTime hcmDateTime = ZonedDateTime.of(dateTimeFromDateAndTime, ZoneId.of("Asia/Ho_Chi_Minh"));
 
        // Convert old classes to Java 8 Date Time
        Instant instantFromDate = new Date().toInstant();
        ZoneId zoneId = TimeZone.getDefault().toZoneId();
        Instant instantFromCalendar = Calendar.getInstance().toInstant();
        ZonedDateTime zonedDateTime = new GregorianCalendar().toZonedDateTime();
 
        // Instant <-> LocalDateTime
        Instant instant = Instant.now();
        LocalDateTime dateTimeFromInstant = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        Instant instantFromLocalDateTime = dateTimeFromInstant.toInstant(ZoneOffset.ofHours(+7));
 
        // Instant <-> LocalDate
        LocalDate localDate = instant.atZone(ZoneId.systemDefault()).toLocalDate();
        Instant instantFromLocalDate = localDate.atStartOfDay(ZoneId.systemDefault()).toInstant();
 
        // Convert Java 8 Date Time to old classes
        Date dateFromInstant = Date.from(Instant.now());
        TimeZone timeZone = TimeZone.getTimeZone(ZoneId.of("Asia/Ho_Chi_Minh"));
        GregorianCalendar gregorianCalendar = GregorianCalendar.from(ZonedDateTime.now());
    }
}