본문 바로가기

자바의 정석 정리

자바의 정석 - 10.3 java.time

10.3.1 time패키지

  • time 패키지 내부의 클래스들은 항상 변경된 새로운 객체 반환
  • 즉, 불변성(immutable)을 가짐
  • 항상 새호운 객체가 반환되어서 동시에 여러 쓰레드가 같은 객체에 접근하는 멀티 쓰레드 환경에서 안전함
java.time : 날짜와 시간을 다루는데 필요한 핵심 클래스들을 제공
java.time.chrono : 표준(ISO)이 아닌 달력 시스템을 위한 클래스 제공
java.time.format : 날짜와 시간을 파싱하고, 형식화하기 위한 클래스들을 제공
java.time.temporal : 날짜와 시간의 필드(field)와 단위(unit)를 위한 클래스들을 제공
java.time.zone : 시간대(time-zone)와 관련된 클래스들을 제공

10.3.2 Period와 Duration

  • Period : 날짜 - 날짜
  • Duration : 시간 - 시간
  • get()을 통해 필드 값을 가져옴
long year = pe.get(ChronoUnit.YEARS); //int getYears()
long month = pe.get(ChronoUnit.MONTHS); //int getMonths()
long day = pe.get(ChronoUnit.DASYS); //int getDays()

long sec = du.get(ChronoUnit.SECONDS); //long getSeconds()
int nano = du.get(ChronoUnit.NANOS); //int getNano()

10.3.3 now()와 of()

  • java.time 클래스들의 객체 생성 방법
  • now()
LocalDate date = LocalDate.now(); //2015-11-23
LocalTime time = LocalTime.now(); //21:54:01.875
LocalDateTime dateTime = LocalDateTime.now(); //2015-11-23T21:54:01.875
ZoneDateTime zone = ZoneDateTime.now(); //2015-11-23T21:54:01.875+09:00[Asia/Seoul]
  • of()
LocalDate date = LocalDate.of(2015, 11, 23); 
LocalTime time = LocalTime.of(23, 59, 59); 
LocalDateTime dateTime = LocalDateTime.of(date, time); 
ZonedDateTime zone = ZonedDateTime.of(dateTime, ZoneId.of("Asia/Seoul")); 

10.3.4 TemporalUnit과 TemporalFeild

  • TemporalUnit : 날짜와 시간의 단위를 저잘한 인터페이스. 구현체는 ChronoUnit[enum]
  • TemporalField : 날짜와 시간의 필드 정의. 구현체는 ChronoField[enum]
AMPM_OF_DAY //오전, 오후
EPOCH_DAY //유닉스 시간부터 몇번째 날
ALIGNED_WEEK_OF_MONTH //그 달의 N번째 주(1~7일 1주, 8~14일 2주, ...)
ALIGNED_WEEK_OF_YEAR //그 해의 N번째 주(1~7일 1주, 8~14일 2주, ...)
INSTANT_SECONDS //년월일을 초단위로 환산(유닉스 시간)
OFFSET_SECONDS //UTC와 시차. ZoneOffset에서만 사용

10.3.5 LocalDate

int getYear()
int getMonthValue()
Month getMonth() //getMonth.getValue() = 12
int getDayOfMonth()
int getDayofYear()
DayOfWeek getDayOfWeek() //getDayOfWeek.getValue() = 5
int lengthOfMonth()
int lengthOfYear() //365. 윤년이면 366
boolean isLeapYear() //윤년여부 확인

10.3.6 LocalTime

int getHour()
int getMinute()
int getSecond()
int getNano()

10.3.7 필드의 값 변경

  • with()
  • LocalDate withYear(int year) LocalTime withHour(int hour) LocalDate with(TemporalField field, long newValue);
  • plus()
  • LocalDate plusYears(long yearsToAdd) LocalTime plusHours(long hourToAdd) LocalTime plus(TemporalAmount amountToAdd)

10.3.8 truncatedTo()

  • LocalTime에 존재
  • 지정된 값 보다 작은 단위의 필드를 0으로 만듦
LocalTime time = LocalTime.of(12, 34, 56); //12시 34분 56초
time = time.truncatedTo(ChronoUnit.HOURS); //12:00

10.3.9 날짜와 시간의 비교

  • isEqual()
  • 연표(chronology)가 다른 두 날짜 비교하기 위해 사용
  • 오직 날짜만 비교
LocalDate kDate = LocalDate.of(1999, 12, 31);
JapanDate jDate = JapanDate.of(1999, 12, 31);

kDate.equals(jDate); //fasle. YEAR_OF_ERA가 다름
kDate.isEqual(jDate); //true

10.3.10 범위

  • .range()
ChronoField.CLOCK_HOUR_OF_DAY.range(); //1-24
ChronoField.HOUR_OF_DAY.range(); //0-23

10.3.11 Instant

  • 에포크 타임(EPOSCH TIME)부터 경과된 시간을 나노초 단위로 표현
  • 단일 진법으로만 다루기 때문에 계산하기 쉽다.
//인스턴스 생성
Instant now1 = Instant.now();
Instant now2 = Instant.ofEpocyhSecond(now1.getEpochSecond());
Instant now3 = Instant.ofEpocyhSecond(now1.getEpochSecond(), now1.getNano());

//값 가져오기
long epochSec = now1.getEpochSecond();
int nano = now1.getNano();
  • java.util.Date를 대체하기 위해 등장함
static Date from(Instant instant)
Instant toInstant()

/*
JDK 1.8 부터 Date 클래스에 Instant로 변환할 수 있는 메서드로 추가됨
*/

10.3.11 LocalDateTime

  • LocalDate + LocalTime
LocalDate date = LocalDate.of(2015, 12, 31); 
LocalTime time = LocalTime.of(12, 34, 56); 

//date + time
LocalDateTime dt1 = LocalDateTime.of(date, time); 
LocalDateTime dt2 = date.atTime(time);
LocalDateTime dt3 = time.atDate(date);
LocalDateTime dt4 = date.atTime(12, 34, 56);
LocalDateTime dt5 = time.atDate(LocalDate.of(2015, 12, 31));
LocalDateTime dt6 = date.atStartOfDay();

//LocalDateTime 인스턴스 생성
LocalDateTime dt7 = LocalDateTime.of(2015, 12, 31 ,12, 34, 56);
LocalDateTime dt8 = LocalDawteTime.now(); 
  • 변환
LocalDateTime dt = LocalDateTime.of(2015, 12, 31 ,12, 34, 56);
LocalDate date = dt.toLocalDate();
LocalTime time = dt.toLocalTime();

10.3.12 ZonedDateTime

  • ZoneId 클래스 사용
  • 일광 절약시간(DST, Daylight Saving Time)을 자동으로 처리
ZoneId zid = ZoneId.of("Asia/Seoul");
ZonedDateTime zdt = dateTime.atZone(zid); //2015-11-23T21:54:01.875+09:00[Asia/Seoul]
  • LocalDate의 atStartOfDay 사용
ZonedDateTime zdt = LocalDAte.now().atStartOfDay(zid); ////2015-11-23T21:54:01.875+09:00[Asia/Seoul]
  • 특정 시간대의 시간
ZoneId zid = ZoneId.of("America/New_York");
ZonedDateTime nTime = ZoneDateTime.now().withZoneSameInstant(zid); 
//2015-12-15T07:52:07.672-05:00[America/New_York]

10.3.13 ZoneOffset

  • UTC로 부터 얼만큼 떨어져 있는지 표현
ZoneOffset krOffset1 = ZonedDateTime.now().getOffset();
//ZoneOffset krOffset2 = ZoneOffset.of("+9");
int krOffset1 = krOffset1.get(ChronoField.OFFSET_SECONDS); //32400

10.3.14 OffsetDateTime

  • ZoneId가 아닌 ZoneOffset을 사용
  • 다른 시간대에 존재하는 컴퓨터 통신에서 사용
ZoneOffset krOffset = ZonedDateTime.now().getOffset();
LocalDate date = LocalDate.of(2015, 11, 23); 
LocalTime time = LocalTime.now(23, 59, 59);

OffsetDateTime odt = OffsetDateTime.of(date, time, krOffset);

10.3.15 ZonedDateTime의 변환

LocalDate toLocalDate()
LocalTime toLocalTime()
LocalDateTime toLocalDateTime()
OffsetDateTime toOffsetDateTime()
long toEpochSecond()
Instant toInstant()

//ZonedDateTime -> GregorianCalendar
GregorianCalendar from(ZonedDateTime zdt)

//GregorianCalendar -> ZonedDateTime
ZonedDateTime toZonedDateTime()

10.3.16 TemporalAdjusters

  • 자주 쓰이는 날짜 계산 메서드가 정의되어 있음
firstDayOfNextYear() //다음해 첫 날
firstDayOfNextMonth() //다음다 첫 날
firstDayOfYear() //올 해의 첫 날
firstDayOfMonth() //이번 달의 첫 날
lastDayOfYear() //올 해의 마지막 날
lastDayOfMonth() //이번 달의 마지막 날
firstInMonth(DayOfWeek dayOfWeek) //이번달의 첫 번째 ?요일
lastInMonth(DayOfWeek dayOfWeek) //이번달의 마지막 ?요일
previous(DayOfWeek dayOfWeek) //지난 ?요일(당일 미포함)
previousOrSame(DayOfWeek dayOfWeek) //지난 ?요일(당일 포함)
next(DayOfWeek dayOfWeek) //다음 ?요일(당일 미포함)
nextOrSame(DayOfWeek dayOfWeek) //다음 ?요일(당일 포함)
dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek) //이번 달의 n번째 ?요일
  • 추상 메서드 하나만 정의되어 있음
@FunctionalInterface
public interface TemporalAdjuster{
    Temporal adjustInto(Temporal temporal);
}

/*
상속을 받아 직접 사용해도 되지만, adjustInto는 내부에서만 사용할 용도로 작성되었가 때문에
구현체에 있는 with() 사용하는 것을 추천
*/
LocalDate today = new LocalDate.now();

today.with(fisrtDayOfNextMonth()) //2016-01-01. 다음달의 첫 날
today.with(firstDayOfMonth()) //2015-12-01. 이번 달의 첫 날

10.3.17 between()

  • 두 날짜의 차이
LocalDate d1 = LocalDate.of(2014, 1, 1);
LocalDate d2 = LocalDate.of(2015, 11, 31);
Period pe = Period.between(d1, d1);

LocalTime t1 = LocalTime.of(00, 00, 00);
LocalTime t2 = LocalTime.of(12, 34, 56);
Duration du = Duration.between(t1, t2);

/*
-get-
long year = pe.get(ChronoUnit.YEARS); //int getYears()
long month = pe.get(ChronoUnit.MONTHS); //int getMonths()
long day = pe.get(ChronoUnit.DASYS); //int getDays()

long sec = du.get(ChronoUnit.SECONDS); //long getSeconds()
int nano = du.get(ChronoUnit.NANOS); //int getNano()

Period와 달리 Duration은 getHours나 getMinutes()같은 메서드가 존재하지 않음.
하지만, LocalTime을 이용하면 가능
*/

LocalTime t = LocalTime.of(0,0).plusSeconds(du.getSeconds());
int hour = t.getHour();
int min = t.getMinute();
int sec = t.getSecond();
int nano = t.getNano();

10.3.18 Period와 Duration

  • Period : 날짜 - 날짜
  • Duration : 시간 - 시간
//of
Period pe = Period.of(1, 12, 31); //1년 12개월 31일
Duration du = Duration.of(60, ChronoUnit.SECONDS); //60초
Duration du2 = Duration.ofSeconds(60); //60초

//with
pe = pe.withYears(2); //1년에서 2년으로 변경
du = du.withSeconds(120); //60초에서 120초로 변경

//사칙연산
pe = pe.minusYears(1).multipliedBy(2); //1년을 빼고, 2배를 곱함
du = du.plusHours(1). dividedBy(60); //1시간을 더하고 60으로 나눈다

//기타
boolean same = Period.between(date1, date2).isZero();
boolean negative = Duration.between(time1, time2).isNegative();
  • 다른 단위로 변환
//Period
long toTotalMonths() //년월일을 월단위로 변환(일 단위는 무시)

//Duration
long toDays() //일단위로 변환
long toHours() //시간 단위로 변환
long toMonutes() //분 단위로 변환
long toMiilis() //천분의 일초 단위로 변환
long toNanos() //나노초 단위로 변환

10.3.19 파싱과 포맷

  • 대부분 DateTimeFormatter를 사용
LocalDate date = LocalDate.of(2016, 1, 2);
String y1 = DateTimeFormatter.ISO_LOCAL_DATE.format(date); //2016-01-02
String y2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
  • 로케일에 종속된 형식화
DateTimeFormatter fo = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
String sh = formatter.format(LocalDAte.now());

FormatStyle.SHORT

10.3.20 출력형식 직접 정의

  • ofPattern()으로 원하는 출력형식 직접 작성가능
ZonedDateTime z = ZonedDateTime.now();
DateTimeFormatter fo = DateTimeFormatter.ofPattern("yyy/MM/dd");

z.format(fo);

10.3.21 문자열을 날짜와 시간으로 파싱

  • parse()
static LocalDateTime parse(CharSequence text)
static LocalDateTime parse(CharSequence text, DateTimeFormatter formatter)
LocalDate date1 = LocalDate.parse("2016-12-11", DateTimeFormatter.ISO_LOCAL_DATE);

DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyy/MM/dd HH:mm:ss");
LocalDate date1 = LocalDate.parse("2016-12-11 23:59:59", pattern);