> Java > java지도 시간 > 본문

Java8의 시간 사용에 대한 자세한 설명(예제 포함)

不言
풀어 주다: 2019-02-01 10:52:13
앞으로
2943명이 탐색했습니다.

이 기사는 Java8의 시간 사용에 대한 자세한 설명을 제공합니다(예제 포함). 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.

왜 새로운 시간 API가 필요한가요?

Java 8 이전의 날짜/시간 API 이전에는 기존 날짜 및 시간 관련 클래스에 많은 문제가 있었으며 주요 문제는 다음과 같습니다.

  1. Java의 날짜/시간 클래스 정의는 Java에서 일관성이 없습니다. util 및 java.sql 패키지에는 날짜 클래스가 있으며, java.text 패키지에는 형식화 및 구문 분석에 사용되는 클래스가 정의되어 있으며 java.sql.Date에는 날짜가 포함되어 있습니다. 날짜만 포함하므로 java.sql 패키지에 포함하는 것은 의미가 없습니다. 게다가 두 클래스 모두 동일한 이름을 갖고 있는데, 이는 그 자체로 매우 나쁜 디자인입니다.

  2. 시간, 타임스탬프, 서식 지정 및 구문 분석에 대해 명확하게 정의된 클래스가 없습니다. 형식 지정 및 구문 분석 요구 사항을 위해 java.text.DateFormat 추상 클래스가 있지만 일반적으로 이러한 요구 사항에는 SimpleDateFormat 클래스가 사용됩니다.

  3. 모든 날짜 클래스는 변경 가능하므로 그 중 어느 것도 스레드로부터 안전하지 않습니다. 이는 Java 날짜 클래스의 가장 큰 문제 중 하나입니다.

  4. 날짜 클래스는 국제화 기능을 제공하지 않고 시간대 지원도 없기 때문에 Java에서 java.util.Calendar 및 java.util.TimeZone 클래스를 도입했지만 이들 역시 위의 모든 문제를 안고 있습니다.

  5. 기존 날짜 및 달력 클래스에 정의된 메서드에는 몇 가지 다른 문제가 있지만 위의 문제를 통해 명확하게 알 수 있습니다. Java에는 강력한 날짜/시간 클래스가 필요하다는 것입니다. 이것이 바로 Joda Time이 Java 날짜/시간 요구 사항에 대한 고품질 대체품으로서 중요한 역할을 하는 이유입니다.

  6. java8

  7.    使用Calendar类实现日期和时间字段之间转换
       使用DateFormat类来格式化和分析日期字符串
       而Date只用来承载日期和时间信息
    로그인 후 복사

    java8 개념 이전 날짜를 사용할 때 참고하세요.

  8. 순간 시간(Instant), 기간(duration), 날짜(date), 시간(time), 시간대(time-zone) 및 기간 (기간). Java 8은 여전히 ​​ISO 달력 시스템을 사용하며 이전 버전과 달리 java.time 패키지의 클래스는 변경이 불가능하고 스레드로부터 안전합니다. 새로운 시간 및 날짜 API는 java.time 패키지에 있습니다. 여기에는 몇 가지 주요 클래스가 있습니다:

Instant - 타임스탬프를 나타냅니다. 즉, 1970년을 기준으로 한 특정 시점을 나타내기 때문입니다. 1월 1일의 오프셋이지만 java.util.Date 클래스와 달리 나노초 수준까지 정확합니다.

  • Duration: 기간, 시차

  • LocalDate - 특정 시간을 포함하지 않습니다. 예: 2019-01-14 생일, 기념일, 가입 날짜 등을 저장하는 데 사용할 수 있습니다.

  • LocalTime - 날짜 없이 시간을 나타냅니다.

  • LocalDateTime - 날짜와 시간이 포함됩니다. 여전히 오프셋 정보 또는 시간대가 없습니다.

  • Period: 기간

  • ZoneOffset: 시간대 오프셋(예: +8:00

  • ZonedDateTime) 시간대, 오프셋은 UTC/그리니치 시간을 기준으로 합니다.

  • 시계: 미국 뉴욕의 현재 시간 가져오기 등

  • java8 시간 API 기능

변경 불가능: 새로운 날짜/시간 API, 모든 클래스는 변경 불가능하므로 멀티스레딩에 좋습니다.

  • 우려 분리: Joda 라이브러리의 몇 가지 장점을 활용하여 새 API는 날짜 시간과 기계 시간을 읽을 수 있습니다. (unix timestamp)는 명확하게 구분되어 있으며 날짜(Date), 시간(Time), 날짜 시간(DateTime), 타임스탬프(unix timestamp) 및 시간대에 대해 서로 다른 클래스를 명확하게 정의합니다. : 모든 클래스에는 메소드가 명확하게 정의되어 있습니다. 예를 들어 현재 인스턴스를 얻으려면 이전과 같이 별도의 클래스를 갖는 대신 모든 클래스에 형식() 및 구문 분석() 메서드를 사용할 수 있습니다. 문제를 더 잘 처리하면 모든 클래스가 팩토리 패턴과 전략 패턴을 사용합니다. 클래스 중 하나의 메서드를 사용하면 다른 클래스와 함께 작업하는 것이 어렵지 않습니다. API 클래스는 더하기, 빼기, 서식 지정, 구문 분석, 날짜/시간에서 개별 부분 추출 등과 같은 일반적인 작업을 완료하기 위한 일련의 메서드를 구현합니다.

  • 확장성: 새로운 날짜/시간 API는 ISO-8601 달력 시스템이지만 IOS가 아닌 달력에도 적용할 수 있습니다.

  • java8 날짜/시간 API 패키지

  • java.time 패키지: 이것은 새로운 Java 날짜/시간 API의 기본 패키지입니다. LocalDate, LocalTime, LocalDateTime, Instant, Period, Duration 등과 같은 모든 주요 기본 클래스는 이 패키지의 일부입니다. 이러한 클래스는 모두 변경이 불가능하고 스레드로부터 안전하며 대부분의 경우 이러한 클래스는 공통 요구 사항을 효과적으로 처리합니다.

  • java.time.chrono 패키지: 이 패키지는 ISO가 아닌 달력 시스템을 위한 일부 일반화된 API를 정의하여 AbstractChronology 클래스를 확장하여 자체 달력 시스템을 만들 수 있습니다.

  • java.time.format包:这个包包含能够格式化和解析日期时间对象的类,在绝大多数情况下,我们不应该直接使用它们,因为java.time包中相应的类已经提供了格式化和解析的方法。

  • java.time.temporal包:这个包包含一些时态对象,我们可以用其找出关于日期/时间对象的某个特定日期或时间,比如说,可以找到某月的第一天或最后一天。你可以非常容易地认出这些方法,因为它们都具有“withXXX”的格式。

  • java.time.zone包:这个包包含支持不同时区以及相关规则的类。

java8 API介绍和使用

LocalDate

LocalDate 依然是一个不可变类,它关注时间中年月日部分

初始化实例
public static LocalDate now():截断当前系统时间的年月日信息并初始化一个实例对象
public static LocalDate of(int year, int month, int dayOfMonth):显式指定年月日信息
public static LocalDate ofYearDay(int year, int dayOfYear):根据 dayOfYear 可以推出 month 和 dayOfMonth
public static LocalDate ofEpochDay(long epochDay):相对于格林零时区时间的日偏移量
…………
로그인 후 복사

示例

// 取当前日期:
LocalDate today = LocalDate.now(); // -> 2019-01-31
// 根据年月日取日期,12月就是12:
LocalDate crischristmas = LocalDate.of(2018, 12, 25); // -> 2018-12-25
// 根据字符串取:
LocalDate endOfFeb = LocalDate.parse("2018-12-25"); // 严格按照ISO yyyy-MM-dd验证,02写成2都不行,当然也有一个重载方法允许自己定义格式

// 如何获取1周后的日期
LocalDate oneToday = today.plus(1, ChronoUnit.WEEKS); // ->2019-02-07
//一年前的日期
LocalDate previousYear = today.minus(1, ChronoUnit.YEARS);
// 取本月第1天:
LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth()); // 2019-01-01
// 取本月第2天:
LocalDate secondDayOfThisMonth = today.withDayOfMonth(2); // 2019-01-02
// 取本月最后一天,再也不用计算是28,29,30还是31:
LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth()); // 2019-01-31
// 取下一天:
LocalDate firstDay = lastDayOfThisMonth.plusDays(1); // 变成了2019-02-01
// 取2019年1月第一个周一
LocalDate firstMonday = LocalDate.parse("2019-01-01").with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)); // 2019-01-07
로그인 후 복사

在java8中,可以使用MonthDay,该类不包含年份信息,当然还有一个类是YearMonth

LocalDate birthday = LocalDate.of(1990, 10, 12);
MonthDay birthdayMd = MonthDay.of(birthday.getMonth(), birthday.getDayOfMonth());
MonthDay today = MonthDay.from(LocalDate.of(2019, 10, 12)); 
System.out.println(today.equals(birthdayMd));
//结果
true
로그인 후 복사
TemporalAdjuster

但是有些时候我们要面临更复杂的时间操作,比如将时间调到下一个工作日,或者是下个月的最后一天,这时候我们可以使用with()方法的另一个重载方法,它接收一个TemporalAdjuster参数,可以使我们更加灵活的调整日期:

LocalDate date7 = date.with(nextOrSame(DayOfWeek.SUNDAY));      // 返回下一个距离当前时间最近的星期日
LocalDate date9 = date.with(lastInMonth(DayOfWeek.SATURDAY));   // 返回本月最后一个星期六
로그인 후 복사

如果本身API不满足你的需求,你还可以创建自定义的TemporalAdjuster接口的实现

LocalTime

类似于 LocalDate,LocalTime 专注于时间的处理,它提供小时,分钟,秒,毫微秒的各种处理

初始化LocalTime实例
public static LocalTime now():根据系统当前时刻获取其中的时间部分内容
public static LocalTime of(int hour, int minute):显式传入小时和分钟来构建一个实例对象
public static LocalTime of(int hour, int minute, int second):通过传入时分秒构造实例
public static LocalTime of(int hour, int minute, int second, int nanoOfSecond):传入时分秒和毫微秒构建一个实例
public static LocalTime ofSecondOfDay(long secondOfDay):传入一个长整型数值代表当前日已经过去的秒数
public static LocalTime ofNanoOfDay(long nanoOfDay):传入一个长整型代表当前日已经过去的毫微秒数
로그인 후 복사

示例

//包含毫秒
LocalTime now = LocalTime.now(); // 11:09:09.240
//不包含毫秒  
LocalTime now = LocalTime.now().withNano(0)); // 11:09:09
//构造时间  
LocalTime zero = LocalTime.of(0, 0, 0); // 00:00:00
LocalTime mid = LocalTime.parse("12:00:00"); // 12:00:00
LocalTime twoHour = now.plusHours(2);
로그인 후 복사

LocalDateTime

LocalDateTime类是LocalDate和LocalTime的结合体,可以通过of()方法直接创建,也可以调用LocalDate的atTime()方法或LocalTime的atDate()方法将LocalDate或LocalTime合并成一个LocalDateTime

LocalDateTime ldt1 = LocalDateTime.of(2017, Month.JANUARY, 4, 17, 23, 52);

LocalDate localDate = LocalDate.of(2017, Month.JANUARY, 4);
LocalTime localTime = LocalTime.of(17, 23, 52);
LocalDateTime ldt2 = localDate.atTime(localTime);
로그인 후 복사

LocalDateTime也提供用于向LocalDate和LocalTime的转化:

LocalDate date = ldt1.toLocalDate();
LocalTime time = ldt1.toLocalTime();
로그인 후 복사

Instant

Instant用于表示一个时间戳,它与我们常使用的System.currentTimeMillis()有些类似,不过Instant可以精确到纳秒(Nano-Second),System.currentTimeMillis()方法只精确到毫秒(Milli-Second)。如果查看Instant源码,发现它的内部使用了两个常量,seconds表示从1970-01-01 00:00:00开始到现在的秒数,nanos表示纳秒部分(nanos的值不会超过999,999,999)。Instant除了使用now()方法创建外,还可以通过ofEpochSecond方法创建:

Instant instant = Instant.ofEpochSecond(120, 100000);
로그인 후 복사

时间差

关于时间差的计算,主要涉及到两个类,年月日的日期间差值的计算使用 Period 类足以,而时分秒毫秒的时间的差值计算则需要使用Duration类。

  • Duration:处理两个时间之间的差值

        LocalDateTime from = LocalDateTime.of(2019, Month.JANUARY, 5, 10, 7, 0);    // 2019-01-05 10:07:00
    LocalDateTime to = LocalDateTime.of(2019, Month.FEBRUARY, 5, 10, 7, 0);     // 2019-02-05 10:07:00
    Duration duration = Duration.between(from, to);     // 表示从 2019-01-05 10:07:00 到 2019-02-05 10:07:00 这段时间
    
    long days = duration.toDays();              // 这段时间的总天数
    long hours = duration.toHours();            // 这段时间的小时数
    long minutes = duration.toMinutes();        // 这段时间的分钟数
    long seconds = duration.getSeconds();       // 这段时间的秒数
    long milliSeconds = duration.toMillis();    // 这段时间的毫秒数
    long nanoSeconds = duration.toNanos();      // 这段时间的纳秒数
    로그인 후 복사

    Duration对象还可以通过of()方法创建,该方法接受一个时间段长度,和一个时间单位作为参数:

    Duration duration1 = Duration.of(5, ChronoUnit.DAYS);       // 5天
    Duration duration2 = Duration.of(1000, ChronoUnit.MILLIS);  // 1000毫秒
    로그인 후 복사
    • Duration的内部实现与Instant类似,也是包含两部分:seconds表示秒,nanos表示纳秒。两者的区别是Instant用于表示一个时间戳(或者说是一个时间点),而Duration表示一个时间段,所以Duration类中不包含now()静态方法。可以通过Duration.between()方法创建

  • Period:处理两个日期之间的差值

    • Period在概念上和Duration类似,区别在于Period是以年月日来衡量一个时间段,比如2年3个月6天

      Period period = Period.of(2, 3, 6);
      로그인 후 복사
  • Period对象也可以通过between()方法创建,值得注意的是,由于Period是以年月日衡量时间段,所以between()方法只能接收LocalDate类型的参数:

    Period period = Period.between(
                LocalDate.of(2019, 1, 5),
                LocalDate.of(2019, 2, 5));
    로그인 후 복사
  • 示例

 LocalDate date = LocalDate.of(2019,01,22);
    LocalDate date1 = LocalDate.now();
    Period period = Period.between(date,date1);
    System.out.println(period.getYears() + "年" +
            period.getMonths() + "月" +
            period.getDays() + "天");

    LocalTime time = LocalTime.of(20,30);
    LocalTime time1 = LocalTime.of(23,59);
    Duration duration = Duration.between(time,time1);
    System.out.println(duration.toMinutes() + "分钟");
로그인 후 복사

ZonedDateTime

无论是我们的 LocalDate,或是 LocalTime,甚至是 LocalDateTime,它们基本是时区无关的,内部并没有存储时区属性,而基本用的系统默认时区。往往有些场景之下,缺乏一定的灵活性。

ZonedDateTime 可以被理解为 LocalDateTime 的外层封装,它的内部存储了一个 LocalDateTime 的实例,专门用于普通的日期时间处理。此外,它还定义了 ZoneId 和 ZoneOffset 来描述时区的概念。

ZonedDateTime 和 LocalDateTime 的一个很大的不同点在于,后者内部并没有存储时区,所以对于系统的依赖性很强,往往换一个时区可能就会导致程序中的日期时间不一致。
而后者则可以通过传入时区的名称,使用 ZoneId 进行匹配存储,也可以通过传入与零时区的偏移量,使用 ZoneOffset 存储时区信息。

初始化实例
public static ZonedDateTime now():系统将以默认时区计算并存储日期时间信息
public static ZonedDateTime now(ZoneId zone):指定时区
public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone):指定日期时间和时区
public static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone)
public static ZonedDateTime ofInstant(Instant instant, ZoneId zone):通过时刻和时区构建实例对象
等等
로그인 후 복사

示例

 ZonedDateTime zonedDateTime = ZonedDateTime.now();
    System.out.println(zonedDateTime); 
    //->2019-01-31T16:27:23.179+08:00[Asia/Shanghai]

    LocalDateTime localDateTime = LocalDateTime.now();
    ZoneId zoneId = ZoneId.of("America/Los_Angeles");
    ZonedDateTime zonedDateTime1 = ZonedDateTime.of(localDateTime,zoneId);
    System.out.println(zonedDateTime1);
    // ->2019-01-31T16:27:23.179-08:00[America/Los_Angeles]


    Instant instant = Instant.now();
    ZoneId zoneId1 = ZoneId.of("GMT");
    ZonedDateTime zonedDateTime2 = ZonedDateTime.ofInstant(instant,zoneId1);
    System.out.println(zonedDateTime2);
    // ->2019-01-31T08:27:23.183Z[GMT]
로그인 후 복사
  • 第一个输出应使用了当前系统日期和时间以及默认的时区。

  • 第二个小例子,LocalDateTime 实例保存了时区无关的当前日期时间信息,也就是这里的年月日时分秒,接着构建一个 ZonedDateTime 实例并传入一个美国时区(西七区)。你会发现输出的日期时间为西七区的 16 点 27 分。

    像这种关联了时区的日期时间就很能够解决那种,换时区导致程序中时间错乱的问题。因为我关联了时区,无论你程序换到什么地方运行了,日期+时区 本就已经唯一确定了某个时刻,就相当于我在存储某个时刻的时候,说明了这是某某时区的某某时间,即便你换了一个地区,也不至于把这个时间按自己当前的时区进行解析并直接使用。

  • 第三个小例子,构建 ZonedDateTime实例的时候,给定一个时刻和一个时区,而这个时刻值就是相对于给定时区的标准时间所经过的毫秒数。

    有关 ZonedDateTime 的其他日期时间的处理方法和 LocalDateTime 是一样的,因为 ZonedDateTime 是直接封装了一个 LocalDateTime 实例对象,所以所有相关日期时间的操作都会间接的调用 LocalDateTime 实例的方法,我们不再赘述。

格式化日期时间

Java 8 的新式日期时间 API 中,DateTimeFormatter 作为格式化日期时间的主要类,它与之前的 DateFormat 类最大的不同就在于它是线程安全的,如果需要的话,可以赋值给一个静态变量。

DateTimeFormatter类提供了许多预定义的格式器,你也可以自定义自己想要的格式。当然根据约定,它还有一个parse()方法是用于将字符串转换成日期的,如果转换期间出现任何错误,它会抛出DateTimeParseException异常。类似的,DateFormatter类也有一个用于格式化日期的format()方法,它出错的话则会抛出DateTimeException异常

再说一句,“MMM d yyyy”与“MMm dd yyyy”这两个日期格式也略有不同,前者能识别出"Jan 2 2018"与"Jan 14 2018"这两个串,而后者如果传进来的是"Jan 2 2018"则会报错,因为它期望月份处传进来的是两个字符。为了解决这个问题,在天为个位数的情况下,你得在前面补0,比如"Jan 2 2018"应该改为"Jan 02 2018"。

public static void main(String[] a){
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
    LocalDateTime localDateTime = LocalDateTime.now();
    System.out.println(formatter.format(localDateTime));

    String str = "2008年08月23日 23:59:59";
    DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
    LocalDateTime localDateTime2 = LocalDateTime.parse(str,formatter2);
    System.out.println(localDateTime2);

}
로그인 후 복사

java8 时间与老版本时间转换

因为java8之前Date是包含日期和时间的,而LocalDate只包含日期,LocalTime只包含时间,所以与Date在互转中,势必会丢失日期或者时间,或者会使用起始时间。如果转LocalDateTime,那么就不存在信息误差。

/Date与Instant的相互转化
Instant instant  = Instant.now();
Date date = Date.from(instant);
Instant instant2 = date.toInstant();
        
//Date转为LocalDateTime
Date date2 = new Date();
LocalDateTime localDateTime2 = LocalDateTime.ofInstant(date2.toInstant(), ZoneId.systemDefault());
        
//LocalDateTime转Date
LocalDateTime localDateTime3 = LocalDateTime.now();
Instant instant3 = localDateTime3.atZone(ZoneId.systemDefault()).toInstant();
Date date3 = Date.from(instant);

//LocalDate转Date
//因为LocalDate不包含时间,所以转Date时,会默认转为当天的起始时间,00:00:00
LocalDate localDate4 = LocalDate.now();
Instant instant4 = localDate4.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
Date date4 = Date.from(instant);


// Calendar to Instant
Instant time = Calendar.getInstance().toInstant();
System.out.println(time);

// TimeZone to ZoneId
ZoneId defaultZone = TimeZone.getDefault().toZoneId();
System.out.println(defaultZone);
 
// ZonedDateTime from specific Calendar
ZonedDateTime gregorianCalendarDateTime = new GregorianCalendar().toZonedDateTime();
System.out.println(gregorianCalendarDateTime);
 
 
GregorianCalendar gc = GregorianCalendar.from(gregorianCalendarDateTime);
System.out.println(gc);
로그인 후 복사

위 내용은 Java8의 시간 사용에 대한 자세한 설명(예제 포함)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:cnblogs.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!