Things You Should Know About Dates in Java

1 Introduction

The time-related libraries in Java are so indescribable that they were forced out of a joda library. There is certainly a reason why the Java time processing library has been complained about.

java.util.Date, java.util.Calendar are not easy to use, but they are barely enough.

At the time of Java 8, maybe because of KPI requirements, they finally decided to do some refactoring of the time base, oh no, it's no longer called refactoring, it's called rewriting.

The function is perfect, but it is too complicated for API call enthusiasts like me. If you don’t believe me, look at the following classes and interfaces:

  1. LocalTime
  2. localDate
  3. LocalDateTime
  4. OffsetDateTime
  5. ZonedDateTime
  6. TemporalAccessor
  7. Temporal
  8. ChronoField
  9. Temporary Adjusters
  10. Temporary Adjuster
  11. TemporalUnit
  12. ChronoUnit
  13. Year
  14. YearMonth
  15. ZoneOffset
  16. ZoneId
  17. Instant
  18. Period
  19. ChronoPeriod
  20. Clock
  21. TemporalAmount
  22. DateTimeFormatter

Of course, not knowing the above classes and interfaces does not affect us calling the API, but it is always right to know a little more.

Of course, we will not introduce all the classes and interfaces here. We will briefly talk about their logic, focusing on some commonly used and used classes, such as the following classes.

  1. localDate
  2. LocalDateTime
  3. DateTimeFormatter
  4. ZoneId
  5. Instant
  6. Duration
  7. Period
  8. Temporary Adjusters

2. LocalDate

2.1 Create

The constructor of LocalDate is private and can only be created through static engineering methods, mainly of and parse.

@Test
public void createLocalDate(){
    LocalDate.now();//今天
    LocalDate.of(2021, 1, 1);
    LocalDate.of(2021, Month.JANUARY, 1);
    LocalDate.parse("2021-01-01");
}

2.2 Calculation

The biggest feature of the new date library is that date calculations are really convenient, and you can basically perform anything you need.

 @Test
public void calcLocalDate(){
    LocalDate now = LocalDate.now();
    now.plusDays(7);//7天之后
    now.plusYears(1);//1年之后
    now.minusMonths(1);//1月之前
    now.minusWeeks(1);//1周之前
}

2.3 Comparison

@Test
public void compareLocalDate(){
    LocalDate now = LocalDate.now();
    LocalDate first = LocalDate.of(2021, 1, 1);
    System.out.println(now.isBefore(first));//now日期是不是早于first
    System.out.println(now.isAfter(first));//now日期是不是晚于first
    System.out.println(now.isEqual(first));//now和first是不是同一天
}

2.4 Others

@Test
public void otherLocalDate(){
    LocalDate now = LocalDate.now();
    now.toEpochDay();//当前日期时间戳对应的天
    now.withYear(2021);//指定年份
    now.until(LocalDate.now().plusDays(36));//计算2个日期的时间区间
    now.atStartOfDay();//一天的开始时间
    now.format(DateTimeFormatter.ISO_DATE_TIME);//格式化时间
}

3. LocalDateTime

The usage methods of LocalDateTime and LocalDate are basically the same, but there is more time part than LocalDate, and their previous methods can basically be applied to each other.

@Test
public void chronoFieldTest(){
    LocalDateTime localDateTime = LocalDateTime.now();
    System.out.println(localDateTime.getLong(ChronoField.MINUTE_OF_HOUR));//当前的分钟
    System.out.println(localDateTime.getLong(ChronoField.HOUR_OF_DAY));//当前是一天的第多少个小时
    System.out.println(localDateTime.getLong(ChronoField.DAY_OF_MONTH));//当前是一个月中的第多少天
    System.out.println(localDateTime.getLong(ChronoField.DAY_OF_YEAR));//当前是一年中的第多少天
    System.out.println(localDateTime.getLong(ChronoField.ALIGNED_WEEK_OF_MONTH));//当前是这个月的第多少周,不是按完整的周计算
    System.out.println(localDateTime.getLong(ChronoField.EPOCH_DAY));//时间戳对应的天
}
@Test
public void chronoUnitTest(){
    LocalDateTime localDateTime = LocalDateTime.now();
    localDateTime.plus(1,ChronoUnit.YEARS);//一年之后
    localDateTime.plus(1,ChronoUnit.HOURS);//一小时之后
    localDateTime.plus(1,ChronoUnit.HALF_DAYS);//半天之后
    localDateTime.plus(1,ChronoUnit.MONTHS);//一月之后
}

4. DateTimeFormatter

DateTimeFormatter is very simple and complex. Basically, you can use the ofPattern method to specify the format of the formatted time.

@Test
public void datetimeFormatter(){
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    LocalDateTime date = LocalDateTime.now();
    System.out.println(formatter.format(date));
    System.out.println(DateTimeFormatter.ISO_LOCAL_DATE.format(date));
    System.out.println(DateTimeFormatter.ISO_LOCAL_TIME.format(date));
    System.out.println(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(date));
    System.out.println(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.MEDIUM).format(date));
    System.out.println(DateTimeFormatter.ofLocalizedTime(FormatStyle.LONG).format(date));
}

5. ZoneId and ZoneOffset

ZoneId is an abstract class, mainly to deal with time zone issues, and ZoneOffset is the implementation class of ZoneId.

In fact, it mainly involves a conversion problem between local time and timestamp.

@Test
public void zoneId(){
    long now = System.currentTimeMillis();
    Instant instant = Instant.ofEpochMilli(now);
    ZoneId zoneId = ZoneId.of("Asia/Shanghai");//东八区北京时间
    LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zoneId);

    System.out.println(now);
    System.out.println(localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli());
    System.out.println(localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli());
    System.out.println(localDateTime.toInstant(ZoneOffset.UTC).toEpochMilli());
}

For the above code, if you can explain why ZoneOffset.UTC is used, which is greater than the milliseconds converted from the correct time zone, you understand the problem of Java time zones.

If you don't know much about time zones, you can take a look at the contents of GTM, UTC and timestamps.

6. Instant

@Test
public void instant() throws InterruptedException {
    //1毫秒
    Instant instant = Instant.ofEpochMilli(1);
    System.out.println(instant.toEpochMilli());

    //1秒再过100万纳秒
    instant = Instant.ofEpochSecond(1,1_000_000_000);
    System.out.println(instant.toEpochMilli());

    Instant start = Instant.now();
    TimeUnit.SECONDS.sleep(2);
    Instant end = Instant.now();
    Duration duration = Duration.between(start,end);
    System.out.println(duration.toMillis());
}

7. Duration与Period

Duration and Period both have the meaning of time interval and time period, but Period emphasizes cycles, such as one year, one month, one week, etc.

Think about such a question: The girlfriend sets the 99th day of each year as the love anniversary, and the 99th day of 2019 is 2019-04-09, then which of the following methods should be used to calculate the love anniversary next year:

  1. Duration.ofDays(365)
  2. Period.ofYears(1)

If your girlfriend is in a bad mood today, would you like to ask how many days are left until the next love anniversary? Which way should it be calculated?

Test it out with the code below, I can only help you so far.

@Test
public void test(){
    LocalDate localDate = LocalDate.parse("2019-04-09");
    System.out.println(localDate.getLong(ChronoField.DAY_OF_YEAR));

    LocalDate durationLocalDate = localDate.plusDays(365);
    System.out.println(durationLocalDate.format(DateTimeFormatter.ISO_DATE));
    System.out.println(durationLocalDate.getLong(ChronoField.DAY_OF_YEAR));
    
    LocalDate periodLocalDate = localDate.plus(Period.ofYears(1));
    System.out.println(periodLocalDate.format(DateTimeFormatter.ISO_DATE));
    System.out.println(periodLocalDate.getLong(ChronoField.DAY_OF_YEAR));
}

In addition, LocalDateTime uses Duration, and LocalDate uses Period.

@Test
public void duration(){
    LocalDateTime now = LocalDateTime.now();
    LocalDateTime localDateTime = now.plusDays(1);
    Duration duration = Duration.between(now, localDateTime);
    System.out.println(duration.toDays());

    Period period = Period.between(now.toLocalDate(), localDateTime.toLocalDate());
    System.out.println(period.getDays());
}
@Test
public void duration(){
    LocalDateTime now = LocalDateTime.now();
    LocalDateTime localDateTime = now.plusYears(1);
    Duration duration = Duration.between(now, localDateTime);
    System.out.println(duration.toMillis());
    System.out.println(Duration.ofDays(1).toHours());
}

8. TemporalAdjuster与TemporalAdjusters

If you want related functions of the scheduling class, TemporalAdjuster is definitely a good choice.

Looking at TemporalAdjusters, we can guess that it should be the tool class of TemporalAdjuster, which provides the following methods:

method illustrate
lastDayOfYear last day of the year
firstDayOfYear first day of the year
1astDayOLMonth last day of next month
next(DayOfWeek) next weekX
firstDayOfMonth 1st day of the month
lastDayOfNextYear last day of next year
lastDayOfNextMonth last day of next month
firstDayOfNextYear first day of next year
firstDayOfNextMonth 1st day of next month
previous(DayOfWeek) last weekX
nextOrSame(DayOfWeek) The next week X, if the current week X is the current day
lastInMonth(DayOfWeek) Last week of the monthX
firstInMonth(DayOfWeek) The first week of the monthX
previousOrSame(DayOfWeek) The previous week X, if the current week X is the current date
dayOfWeekInMonth(int,DayOfWeek) Week X of the month Y, e.g. Mother's Day, 2nd Sunday in May

How to use it?

Look at some small examples to make it clear:

@Test
public void temporalAdjusters(){
    LocalDate now = LocalDate.now();
    LocalDate tmp;
    //下一个星期五
    TemporalAdjuster temporalAdjuster = TemporalAdjusters.next(DayOfWeek.FRIDAY);
    tmp = now.with(temporalAdjuster);
    System.out.println(tmp.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

    //下一个星期五,如果当前日期是星期五,那么就是当前日期
    temporalAdjuster = TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY);
    tmp = now.with(temporalAdjuster);
    System.out.println(tmp.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

    temporalAdjuster = TemporalAdjusters.lastDayOfMonth();
    tmp = now.with(temporalAdjuster);
    System.out.println(tmp.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

    //当月月的最后一个周五
    temporalAdjuster = TemporalAdjusters.lastInMonth(DayOfWeek.FRIDAY);
    tmp = now.with(temporalAdjuster);
    System.out.println(tmp.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

    //当月月第一个周六
    temporalAdjuster = TemporalAdjusters.firstInMonth(DayOfWeek.SATURDAY);
    tmp = now.with(temporalAdjuster);
    System.out.println(tmp.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

    //母亲节:5月第2个星期天
    temporalAdjuster = TemporalAdjusters.dayOfWeekInMonth(2,DayOfWeek.SUNDAY);
    tmp = now.withMonth(5).with(temporalAdjuster);
    System.out.println(tmp.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

    //父亲节:6月第3个星期天
    temporalAdjuster = TemporalAdjusters.dayOfWeekInMonth(3,DayOfWeek.SUNDAY);
    tmp = now.withMonth(6).with(temporalAdjuster);
    System.out.println(tmp.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}

9. GTM, UTC and timestamps

9.1 GMT

GMT (Greenwish Mean Time): Greenwich Mean Time, refers to the standard time of the Royal Greenwich Observatory located in the suburbs of London.

Why use this time as standard time?

Because the prime meridian is defined as the meridian passing through there.

Why is the prime meridian defined as the meridian passing there?

You have so many questions, the movie knows too many characters without a happy ending.

Noon GMT is when the sun crosses the Greenwich meridian, which is when it is at its highest point above Greenwich. Due to the uneven speed of the Earth's elliptical orbit, this moment may be 16 minutes away from actual solar time. The Earth's daily rotation is somewhat irregular and is slowly decelerating.

Therefore, GMT is no longer used as standard time. The current standard time is Coordinated Universal Time (UTC), which is provided by atomic clocks.

9.2 UTC

UTC (Coordinated Universal Time): Universal Universal Time, Universal Standard Time, International Coordinated Time

Although GMT is not precise enough, we usually make me GMT and UTC equivalent.

9.3 Timestamp

Timestamp refers to the number of seconds (10 digits) or milliseconds (13 digits) that have elapsed since Greenwich Mean Time (GMT): 1970-01-01 00:00:00 to the current time.

Therefore, from the definition of the timestamp, we know that the timestamp has nothing to do with the time zone, and there is no local time conversion problem. Therefore, it is best not to add or subtract when storing the timestamp, but only when using the local time .

Although the timestamp does not need to be added or subtracted, it does need to be converted to the local time, because we know from the definition of the timestamp that it is associated with the local time GMT.

Therefore, the time zone is required to convert the timestamp to the local time. The general process is as follows:

  1. Timestamp -> GMT time
  2. GMT time + time zone offset -> local time, for example, we are in East Eighth District, so our time is GMT+8

Of course, when we calculate, we usually perform timestamp addition and subtraction first, and then convert it to time. There is no problem with the result, and it is easy to be misunderstood logically.

{{o.name}}
{{m.name}}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=324094525&siteId=291194637