LocalDateTime for Elegant Handling of Time

Foreword

LocalDate, LocalTime and LocalDateTime are new date processing classes in JDK1.8, which can be faster A more elegant and thread-safe way to handle dates. DateTimeFormatter can customize the date format obtained based on LocalDate, LocalTime and LocalDateTime, and Thread Safety. This article will introduce its common usage.

Text

1. Get the current date and time

LocalDate, LocalTime and LocalDateTime provide the static method now() to get the current date and time.

LocalDate date = LocalDate.now();
LocalTime time = LocalTime. now();
LocalDateTime dateTime = LocalDateTime. now();
System.out.println("date: " + date.toString());
System.out.println("time: " + time.toString());
System.out.println("date time: " + dateTime.toString());
Copy Code

2. Date time format

Use DateTimeFormatter to format the obtained date and time according to the preset format.

1. Format LocalDate

DateTimeFormatter dateFormatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter dateFormatter2 = DateTimeFormatter.ofPattern("yyyyMMdd");
DateTimeFormatter dateFormatter3 = DateTimeFormatter.ofPattern("yyyy.MM.dd");
DateTimeFormatter dateFormatter4 = DateTimeFormatter.ofPattern("yyyy MM dd day");
LocalDate date = LocalDate.now();
System.out.println("date -> " + date.toString());
String formatDate1 = dateFormatter1. format(date);
String formatDate2 = dateFormatter2. format(date);
String formatDate3 = dateFormatter3. format(date);
String formatDate4 = dateFormatter4. format(date);
System.out.println("yyyy-MM-dd -> " + formatDate1);
System.out.println("yyyyMMdd -> " + formatDate2);
System.out.println("yyyy.MM.dd -> " + formatDate3);
System.out.println("yyyy MM dd day -> " + formatDate4);
Copy Code

2. Format LocalTime

DateTimeFormatter timeFormatter1 = DateTimeFormatter.ofPattern("HH:mm:ss");
DateTimeFormatter timeFormatter2 = DateTimeFormatter.ofPattern("HHmmss");
DateTimeFormatter timeFormatter3 = DateTimeFormatter.ofPattern("HH mm ss");
DateTimeFormatter timeFormatter4 = DateTimeFormatter.ofPattern("HH hour mm minute ss second");
LocalTime time = LocalTime. now();
System.out.println("time -> " + time.toString());
String formatTime1 = timeFormatter1. format(time);
String formatTime2 = timeFormatter2. format(time);
String formatTime3 = timeFormatter3. format(time);
String formatTime4 = timeFormatter4. format(time);
System.out.println("HH:mm:ss -> " + formatTime1);
System.out.println("HHmmss -> " + formatTime2);
System.out.println("HH mm ss -> " + formatTime3);
System.out.println("HH hour mm minute ss second -> " + formatTime4);
Copy Code

3. Format LocalDateTime

DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
DateTimeFormatter dateTimeFormatter3 = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss");
DateTimeFormatter dateTimeFormatter4 = DateTimeFormatter.ofPattern("yyyy year MM month dd day HH hour mm minute ss second");
LocalDateTime dateTime = LocalDateTime. now();
System.out.println("date time -> " + dateTime);
String formatDateTime1 = dateTimeFormatter1. format(dateTime);
String formatDateTime2 = dateTimeFormatter2. format(dateTime);
String formatDateTime3 = dateTimeFormatter3. format(dateTime);
String formatDateTime4 = dateTimeFormatter4. format(dateTime);
System.out.println("yyyy-MM-dd HH:mm:ss -> " + formatDateTime1);
System.out.println("yyyyMMddHHmmss -> " + formatDateTime2);
System.out.println("yyyy.MM.dd HH:mm:ss -> " + formatDateTime3);
System.out.println("yyyy year MM month dd day HH hour mm minute ss second -> " + formatDateTime4);
Copy Code

3. Date time string to LocalDateTime

You can also use DateTimeFormatter to read date and time strings in pre-formatted formats.

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
TemporalAccessor parsedDateTime = dateTimeFormatter. parse("2021-07-01 18:00:00");
LocalDateTime dateTime = LocalDateTime. from(parsedDateTime);
Copy Code

4. Conversion between date and time

It is convenient to convert between LocalDate, LocalTime and LocalDateTime.

LocalDateTime dateTime = LocalDateTime.now();
LocalDate date = dateTime.toLocalDate();
LocalTime time = dateTime.toLocalTime();
LocalDateTime gotDateTime = LocalDateTime.of(date, time);
System.out.println("date time: " + dateTime.toString());
System.out.println("date: " + date.toString());
System.out.println("time: " + time.toString());
System.out.println("getted date time: " + gottedDateTime.toString());
Copy Code

LocalDate, LocalTime and LocalDateTime provide the static method of() to construct itself to LocalDateTime< /strong> as an example, the method signature is as follows.

public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute)
public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second)
public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond)
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute)
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second)
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond)
public static LocalDateTime of(LocalDate date, LocalTime time)
Copy Code

5. Get the day of the year (month, week)

LocalDate and LocalDateTime can easily get the day of the year (month, week).

LocalDate date = LocalDate.now();
LocalDateTime dateTime = LocalDateTime. now();

int dateDayOfYear = date. getDayOfYear();
int dateTimeDayOfYear = dateTime. getDayOfYear();
System.out.println("date day of year: " + dateDayOfYear);
System.out.println("date time day of year: " + dateTimeDayOfYear);

int dateDayOfMonth = date. getDayOfMonth();
int dateTimeDayOfMonth = dateTime. getDayOfMonth();
System.out.println("date day of month: " + dateDayOfMonth);
System.out.println("date time day of month: " + dateTimeDayOfMonth);

DayOfWeek dateDayOfWeek = date. getDayOfWeek();
DayOfWeek dateTimeDayOfWeek = dateTime.getDayOfWeek();
System.out.println("date day of week: " + dateDayOfWeek.getValue());
System.out.println("date time day of week: " + dateTimeDayOfWeek.getValue());
Copy Code

6. Get the total number of days in a month

LocalDate and LocalDateTime can get the total number of days in a month, and the way to get it is as follows.

LocalDate date = LocalDate.now();
LocalDate lastDayOfMonth = date.with(TemporalAdjusters.lastDayOfMonth());
System.out.println("days of month: " + lastDayOfMonth.getDayOfMonth());

LocalDateTime dateTime = LocalDateTime. now();
LocalDateTime lastDateTimeOfMonth = dateTime.with(TemporalAdjusters.lastDayOfMonth());
System.out.println("days of month: " + lastDateTimeOfMonth.getDayOfMonth());
Copy Code

7. Date and time addition and subtraction

LocalDate, LocalTime and LocalDateTime can add and subtract date and time. Take LocalDate as an example to illustrate.

LocalDate date = LocalDate.of(2021, 1, 1);
LocalDate fiveDaysAgo = date. minus(5, ChronoUnit. DAYS);
LocalDate fiveDaysLater = date. plus(5, ChronoUnit. DAYS);
System.out.println("today: " + date.toString());
System.out.println("five days ago: " + fiveDaysAgo.toString());
System.out.println("five days later: " + fiveDaysLater.toString());
Copy Code

VIII. Date and time comparison

LocalDate, LocalTime and LocalDateTime can realize the comparison between dates and times, and LocalDate is used as an example to illustrate.

LocalDate date = LocalDate.of(2021, 1, 1);
LocalDate fiveDaysAgo = date. minus(5, ChronoUnit. DAYS);
LocalDate fiveDaysLater = date. plus(5, ChronoUnit. DAYS);

System.out.println("compare result bwtween date and fiveDaysAgo: " + date.compareTo(fiveDaysAgo));
System.out.println("compare result bwtween date and fiveDaysLater: " + date.compareTo(fiveDaysLater));
System.out.println("compare result bwtween date and date: " + date.compareTo(date));
Copy Code

The result of the comparison is the difference between the two dates and times. By judging whether the comparison result is positive or negative, the order of the dates and times can be judged.

9. Timestamp processing

Take LocalDateTime as an example to demonstrate how to convert between LocalDateTime and timestamp (Pay attention to the processing of time zone).

1. Timestamp converted to LocalDateTime

The sample code is as follows.

public class LocalDateTimeLearnTest {

    @Test
    public void timestamp converted to formatted time() {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter
                .ofPattern("yyyy-MM-dd'T'HH:mm:ss");
        
        // 2022-10-01T10:00:00
        long timeStamp = 1664589600000L;

        LocalDateTime localDateTime_8 = LocalDateTime.ofEpochSecond(
                timeStamp / 1000, 0, ZoneOffset.ofHours(8));
        LocalDateTime localDateTime_0 = LocalDateTime.ofEpochSecond(
                timeStamp / 1000, 0, ZoneOffset.ofHours(0));
        System.out.println(dateTimeFormatter.format(localDateTime_8));
        System.out.println(dateTimeFormatter.format(localDateTime_0));
    }

}
Copy Code

The running results are as follows.

2. LocalDateTime conversion timestamp

The sample code is as follows.

public class LocalDateTimeLearnTest {

    @Test
    public void formatted time converted to timestamp() {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter
                .ofPattern("yyyy-MM-dd'T'HH:mm:ss");

        // Get the formatted time LocalDateTime
        String dateTimeString = "2022-10-01T10:00:00";
        TemporalAccessor temporalAccessor = dateTimeFormatter. parse(dateTimeString);
        LocalDateTime dateTime = LocalDateTime. from(temporalAccessor);
        
        // calculate timestamp
        long timeStamp_8 = dateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        long timeStamp_0 = dateTime.toInstant(ZoneOffset.ofHours(0)).toEpochMilli();
        System.out.println("Dongba district time stamp:" + timeStamp_8);
        System.out.println("Zero time zone timestamp:" + timeStamp_0);

        // Calculate the hours difference between East Eight District and zero time zone
        long diff = (timeStamp_0 - timeStamp_8) / 1000 / 60 / 60;
        System.out.println("The hours difference between East Eighth District and zero time zone:" + diff);
    }

}
Copy Code

The running results are as follows.

10. Why thread safety

First explain why SimpleDateFormat thread is not safe. It is known that SimpleDateFormat is a class for formatting and analyzing Date. When the SimpleDateFormat object is declared as a static variable, SimpleDateFormat< /strong> Object usage is thread-unsafe. Take the format() method of SimpleDateFormat as an example to see its implementation.

The format() method will eventually call the following implementation.

private StringBuffer format(Date date, StringBuffer toAppendTo,
                            FieldDelegate delegate) {
    // Called thread-unsafe Calendar object
    calendar. setTime(date);

    boolean useDateFormatSymbols = useDateFormatSymbols();

    for (int i = 0; i < compiledPattern. length; ) {
        int tag = compiledPattern[i] >>> 8;
        int count = compiledPattern[i + + ] & 0xff;
        if (count == 255) {
            count = compiledPattern[i + + ] << 16;
            count |= compiledPattern[i + + ];
        }

        switch (tag) {
        case TAG_QUOTE_ASCII_CHAR:
            toAppendTo.append((char)count);
            break;

        case TAG_QUOTE_CHARS:
            toAppendTo.append(compiledPattern, i, count);
            i + = count;
            break;

        default:
            subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
            break;
        }
    }
    return toAppendTo;
}
Copy Code

calendar is a Calendar object inherited from the parent class DateFormat by SimpleDateFormat, if SimpleDateFormat If the object is declared as a static variable, there will be multiple threads using the SimpleDateFormat object at the same time, so multiple threads call the format() method of SimpleDateFormat at the same time , it will cause multiple threads to call the setTime() method of Calendar at the same time, and the threads will affect each other, so the thread is not safe. Let’s demonstrate it with a simple example.

public class PrintDate {

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

    public void printDate(Date date) {
        System.out.println(Thread.currentThread().getName() + " -> " + sdf.format(date));
    }

}
Copy Code

The test method is as follows.

public class PrintDateTest {

    private PrintDate printDate;

    @Before
    public void setUp() {
        printDate = new PrintDate();
    }

    @Test
    public void givenMultiThreads_whenPrintDateBySimpleDateFormat_thenThreadUnsafe() {
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                2, 10, 10, TimeUnit. SECONDS, new ArrayBlockingQueue<>(15));
        
        threadPool. execute(() -> {
            Date date = new Date(121, Calendar. JANUARY, 1);
            Thread.currentThread().setName(date.toString());
            for (int i = 0; i < 50; i ++ ) {
                printDate. printDate(date);
            }
        });
        threadPool. execute(() -> {
            Date date = new Date(121, Calendar. JANUARY, 2);
            Thread.currentThread().setName(date.toString());
            for (int i = 0; i < 50; i ++ ) {
                printDate. printDate(date);
            }
        });

        LockSupport. parkNanos(1000 * 1000 * 1000L);
    }

}
Copy Code

Enable two threads to cycle and call the printDate() method of PrintDate 50 times, and the result is as follows.

It was found that there was an inconsistency between the incoming date and the printed date. Indicates that the use of the SimpleDateFormat object is thread-unsafe when the SimpleDateFormat object is declared as a static variable

So why are LocalDate, LocalTime and LocalDateTime thread-safe. Let’s take a look at their field signatures.

LocalDate field signature.

public final class LocalDate
        implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable {

    // omitted

    private final int year;

    private final short month;

    private final short day;

    // omitted

}
Copy Code

LocalTime field signature.

public final class LocalTime
        implements Temporal, TemporalAdjuster, Comparable<LocalTime>, Serializable {

    // omitted

    private final byte hour;

    private final byte minute;

    private final byte second;

    private final int nano;

    // omitted

}
Copy Code

LocalDateTime field signature.

public final class LocalDateTime
        implements Temporal, TemporalAdjuster, ChronoLocalDateTime<LocalDate>, Serializable {

    // omitted

    private final LocalDate date;

    private final LocalTime time;

    // omitted

}
Copy Code

LocalDate, LocalTime and LocalDateTime field signatures for date and time are private final, which means that once they are specified date and time , it cannot be changed. Second, their changes to the datetime will return a new object. The thread-safe implementation of LocalDate, LocalTime and LocalDateTime is the same as the thread-safe implementation of String, String class is also private final, and operations on strings will return a new string object.

Summary

LocalDate, LocalTime and LocalDateTime are used more than Date, SimpleDateFormat and Calendar is more convenient and safe to use. Making good use of LocalDate, LocalTime and LocalDateTime can make the processing of date and time more elegant.

syntaxbug.com © 2021 All Rights Reserved.