무작정 개발.Vlog

[Java8] Date와 Time

by 무작정 개발
반응형

이번에는 Date, Time API에 대해 정리할 것이다.

 

 

1. Date와 Time 소개

 

(1) 등장 배경

 

public static void main(String[] args) {

	Date date = new Date();
	Calendar calendar = new GregorianCalendar();
	SimpleDateFormat dateFormat = new SimpleDateFormat();
}

Java8 이전에 사용되는 날짜와 시간 API는 Date, Calendar, GregorianCalendar 등이 있었는데 여러모로 불편함을 유발했습니다.

 

[ 문제점 ]

 

1. 클래스 이름이 명확하지 않다.

 

Date date = new Date();
long time = date.getTime();

날짜 클래스 중 Date는 Date인데도 불구하고 시간도 사용 가능하고, TimeStamp도 표현할 수 있습니다. 사실상 TimeStamp라 볼 수 있고, 시간을 가져와도 이 시간 값은 우리가 아는 시간이 아닌 에폭 타임이라 하여 세계 표준시(UTC)로 1970년 1월 1일 00시 00분 00초를 기준으로 현재까지 흐른 모든 시간을

초(sec) 단위로 표현한 것입니다.

 

2. Date 객체가 mutable 하여 thread unsafe

 

public static void main(String[] args) throws InterruptedException {

    Date date = new Date();
    long time = date.getTime();
    System.out.println("date = " + date);
    Thread.sleep(1000 * 3); // 3초 sleep
    Date after3Seconds = new Date();
    System.out.println("after3Seconds = " + after3Seconds);
	
    // setTime()를 사용하면 객체의 시간값을 변경할 수 있다.
    after3Seconds.setTime(time);
    System.out.println("after3Seconds = " + after3Seconds);
}
/*
[실행 결과]
date = Thu Oct 29 20:22:24 KST 2020
after3Seconds = Thu Oct 29 20:22:27 KST 2020
after3Seconds = Thu Oct 29 20:22:24 KST 2020
*/

setTime()를 사용하여 객체의 시간값을 변경할 수 있는데 이처럼 상태(Status)를 변경할 수 있는 객체를  mutable 객체, 

상태를 변경할 수 없는 객체를 immutable 객체라고 합니다.

 

-> mutable 객체는 멀티 스레드(multi thread) 환경에서 안전하게 사용하기 어렵습니다.

 

-> 그리고 thread unsafe하다는 의미는 하단 그림처럼 하나의 Date 인스턴스의 값을 각각 다른 Thread에 접근해서 변경이 가능하면 기존에 사용하던 Thread에서 변경되어 잘못된 Date정보를 가져와서 버그가 발생할 위험이 있습니다.

 

Thread Unsafe
Thread Unsafe

3. 버그 발생 여지가 많다.

  • Thread unsafe 할 뿐만 아니라 사용법 그 자체에서도 사용법에 대해 오해할 수 있어 버그 발생 여지가 많다.
Calendar birthDay = new GregorianCalendar(1997, 5, 27);

-> 만약 생일이 1997년 5월 25일이라고 할 때 위의 코드는 틀리다고 말할 수 있습니다.

GregorianCalendar에서 month는 0부터 시작하기 때문에 5를 넣으면 6월이라는 의미가 됩니다. 그렇기에 4를 넣어야 하고 헷갈리지 않게 하기 위해서 상수값을 쓰곤 합니다.

 

4. 이러한 이유 때문에 Java 8 이전에는 Joda-Time을 사용했습니다.

Joda - Time

 

Joda-Time - Home

Releases Release 2.12.1 is the current latest release. This release is considered stable and worthy of the 2.x tag. See the change notes for full details. Joda-Time requires Java SE 5 or later and has no dependencies. There is a compile-time dependency on

www.joda.org


2. Date, Time 주요 API

 

(1) 주요 API 특징

  • Java 8부터 기계용 시간(machine time), 인류용 시간(human time)으로 나눌 수 있다.
    • 기계용 시간은 EPOCK (1970년 1월 1일 0시 0분 0초)부터 현재까지의 타임스탬프를 표현
    • 인류용 시간은 우리가 흔히 사용하는 연, 월, 일, 시, 분, 초 등을 표 현
  • 타임스탬프는 Instant를 사용한다.
  • 특정 날짜(LocalDate), 시간(LocalTime), 일시(LocalDateTime)를 사용할 수 있다.
  • 기간을 표현할 때는 Duration(시간 기반)과 Period(날짜 기반)을 사용할 수 있다.
  • DateTimeFormatter를 사용해 일시를 특정한 문자열로 포매팅할 수 있다.

 

(2) 기계용 시간(machine time)을 사용 & 표현하는 방법 

  • Instant.now() : 현재 UTC(GMT)를 반환
  • Universal Time Coordinated == Greenwich Mean Time
public static void main(String[] args) throws InterruptedException {

    Instant instant = Instant.now();//기준시 UTC (GMT)
    System.out.println("instant = " + instant);

    ZoneId zone = ZoneId.systemDefault();
    System.out.println("zone = " + zone);
    ZonedDateTime zonedDateTime = instant.atZone(zone);
    System.out.println("zonedDateTime = " + zonedDateTime);
}
/*
[ 실행 결과 ]
instant = 2020-10-29T11:59:22.897293900Z
zone = Asia/Seoul
zonedDateTime = 2020-10-29T20:59:22.897293900+09:00[Asia/Seoul]
*/

1. ZoneId.systemDefault();

-> 현재 시스템상의 zone 정보를 반환 (ex:Asia/Seoul)

 

2. instant.atZone(zone);

-> UTC 기준이 아닌 zone의 위치 기반의 시간을 반환

 

(3) 인류용 시간(human time)을 사용 & 표현하는 방법 

  • LocalDate와 LocalDateTime이 있음.
    • LocalDate : 년/월/일 까지 표현할 때 사용
    • LocalDateTime : 년/월/일/시/분/초 까지 표현할 때 사용
public static void main(String[] args) {

	LocalDateTime now = LocalDateTime.now();
	System.out.println("now = " + now);
    
	LocalDateTime birthDay = LocalDateTime.of(1988, Month.JUNE, 10, 0, 0, 0);
	ZonedDateTime nowInUTC = ZonedDateTime.now(ZoneId.of("UTC"));
	System.out.println("nowInUTC = " + nowInUTC);
    
	ZonedDateTime birthDayByUTC = ZonedDateTime.of(1988, Month.JUNE.getValue(),10,0,0,0,0, ZoneId.of("UTC"));
	System.out.println("birthDayByUTC = " + birthDayByUTC);
}

 

1. LocalDateTime.now()

-> 현재 시스템 zone에 해당하는(Local) 일시를 반환

 

2. LocalDateTime.of(1988, Month.JUNE, 10, 0, 0, 0);

-> 로컬(Local)의 특정 일시를 반환 -> 상단 코드에서는 1988년 6월 19일 0시 0분 0초를 반환

 

3. ZonedDateTime.now(Zoneld.of("UTC"));

-> 특정 zone의 현재 시간을 반환

 

4. ZonedDateTime.of(1988, Month.JUNE.getValue(), 10,0,0,0,0,Zoneld.of("UTC"));

-> 특정 zone의 특정 일시를 반환

 

(4) 기간을 표현하는 방법

  • Period : 날짜 기간 단위를 표현할 때 사용
  • Duration : 시간 단위 기간을 표현할 때 사용
public static void main(String[] args) {

    LocalDate today = LocalDate.now();
    LocalDate birthDay = LocalDate.of(2020, Month.JUNE, 10);

    Period period = Period.between(birthDay, today);
    System.out.println(period.getMonths()+"개월 "+period.getDays()+"일");

    Period until = today.until(birthDay);
    System.out.println("until.get(ChronoUnit.DAYS) = " + until.get(ChronoUnit.DAYS));

    Instant now = Instant.now();
    Instant plus = now.plus(10, ChronoUnit.SECONDS);
    Duration duration = Duration.between(now, plus);
    System.out.println(duration.getSeconds());
}

 

1. Period.between(birthDay, today)

-> 올해 생일 날짜와 오늘과 비교하여 Period 타입의 인스턴스로 반환

 

2. Period until = today.until(birthDay)

-> LocalDate 객체의 until 메서드를 통해 전달한 인자 값과 인스턴스의 기간을 계산한 Period 타입의 인스턴스를 반환

 

3. Duration.between(now, plus)

-> 현재 시간과 10초 뒤의 시간을 인스턴스로 만든 뒤 비교하여 Duration 타입의 인스턴스로 반환

 

(5) 파싱 또는 포매팅 (Parsing or format)

    • LocalDateTime을 가지고 문자열을 LocalDateTime으로 또는 반대로 변환해주는 방법
    • LocalDateTime.parse(String, DateTimeFormatter);
    • 기본 정의 포매팅 상수 정보와 패턴 정보 참조 링크
    • DateTimeFormatter(Java Platform SE 8)
 

DateTimeFormatter (Java Platform SE 8 )

Parses the text using this formatter, without resolving the result, intended for advanced use cases. Parsing is implemented as a two-phase operation. First, the text is parsed using the layout defined by the formatter, producing a Map of field to value, a

docs.oracle.com

 

public static void main(String[] args) {

    LocalDateTime now = LocalDateTime.now();
    DateTimeFormatter MMddyyyy = DateTimeFormatter.ofPattern("MM/dd/yyyy");
    System.out.println(now.format(DateTimeFormatter.BASIC_ISO_DATE));
    System.out.println(now.format(MMddyyyy));

    LocalDate birthDay = LocalDate.parse("06/10/1988", MMddyyyy);
    System.out.println(birthDay);
}

Reference

인프런-더 자바, Java8_백기선

 

더 자바, Java 8 - 인프런 | 강의

자바 8에 추가된 기능들은 자바가 제공하는 API는 물론이고 스프링 같은 제 3의 라이브러리 및 프레임워크에서도 널리 사용되고 있습니다. 이 시대의 자바 개발자라면 반드시 알아야 합니다. 이

www.inflearn.com

Catsbi's DLog

 

Date와 Time 소개

1. Date와 Time소개

catsbi.oopy.io

 

반응형

블로그의 정보

무작정 개발

무작정 개발

활동하기