프로그래밍언어/Java

LocalDate, LocalTime, LocalDateTime 날짜 타입 사용법 계산 비교 타입 월 마지막 날짜 찾기 Rest API Response Json String 문자열 변환

by 앵과장 2022. 9. 7. 09:34
반응형

날짜 처리하는 내용은 이상하게 항상 검색하게 되는데..

참 이거 맨날 할때마다 외워지지도 않고 검색하는게 당연하기 때문에

15년넘게 검색을 했으니 이제는 좀 정리할때도 된것같아서 정리를 해보자!!

LocalDate, LocalTime, LocalDateTime

자바에서는 각 버전별로 사용해왔었던 날짜처리 클래스가 있는데 가볍게 설명하고 

최근 가장많이 사용하고있는 LocalDate, LocalTIme, LocalDateTime 에 대한 

날짜 타입 비교, 계산, 포맷, 변환, Josn 표기방법까지 알아보자!!

 

날짜 타입의 변천사

Java 1.0 java.util.Date
날짜와 시간관련 기능을 제공

Date 라는 클래스의 이름과 달리 특정 시점을 날짜가 아닌 밀리초 단위로 표현

Date date = new Date(117, 8, 21);

// 출력 결과
// Thu Sep 21 00:00:00 KST 2017

Java 1.1 Calendar 

Date 여러메소드를 deprecate 하고 java.util.Calendar 클래스 제공

Calendar 클래스역시 에러를 일으킬수있는 설계 문제가 있었고 DateFormat 같은 일부 기능은

Date 클레스에서만 작동

DateFormat 문제로 두스레드가 동시에 하나의 포매터로 날짜를 파싱할때 예기치 못한 오류가 발생하는 이슈

Date, Calendar 모두 가변 클래스로 유지보수가 어려움 

 

그래도 자바에서 제공하는게 이것뿐이라 꾸역꾸역 잘써왔네요 !!

 

Java 1.8 LocalDate, LocalTime, LocalDateTime

LocalDate 인스턴스는 시간을 제외한 날짜를 표현하는 불변객체

final 로 처리되기때문에 thread safe하게된다.

정적팩토리 메소드로 of로 LocalDate 인스턴스 표현가능

 

LocalDate, LocalTime LocalDateTime 사용방법

// 정적팩토리 메서드 of로 인스턴스를 만든다.
LocalDate date = LocalDate.of(2022, 9, 10); // 2022-09-10


// 각 항목들을 가져올 수 있다. 
int year = date.getYear(); //2022
Month month = date.getMonth(); // SEPTEMBER
int dayOfMonth = date.getDayOfMonth();// 10

DayOfWeek dayOfWeek = date.getDayOfWeek(); //THURSDAY
int len = date.lengthOfMonth(); // 30 (9월의 일 수)
boolean leapYear = date.isLeapYear(); // false (윤년 이냐?)
// 현재 날짜를 얻는다.
LocalDate currentDate = LocalDate.now();

//파라미터로 전달받은 날짜 정보를 저장한 LocalDate 객체 리턴
LocalDate targetDate = LocalDate.of(2022,11,12);
 //결과 : 2022-11-12


//로컬컴퓨터 현재시간 정보를 저장한 LocalDate 객체 반환
LocalTime currentTime = LocalTime.now();  

//파라미터로 전달받은 시간을 저장한 LocalTime 객체 리턴
LocalTime targetTime = LocalTime.of(12,33,35,22); 
// 결과 : 12:32:33.0000022

// 로컬 컴퓨터의 현재 날짜와 시간 정보
LocalDateTime currentDateTime = LocalDateTime.now();    
// 결과 : 2022-11-12T16:34:30.388

LocalDateTime targetDateTime = LocalDateTime.of(2022, 11, 12, 12, 32,22,3333);
// 여기도 second,nanoSecond 매개변수는 필수가 아닌 선택입니다.
// 결과 : 2022-11-12T12:32:22.000003333
int year = date.get(ChronoField.YEAR);
int month = date.get(ChronoField.MONTH_OF_YEAR);
int day = date.get(ChronoField.DAY_OF_MONTH);

LocalDateTime 날짜 계산하는 방법

LocalDateTime currentDateTime = LocalDateTime.now();
// 더 하기는 plus***() 빼기는 minus***()
// currentDateTime.plusYears(long) or minusYears(long)
currentDateTime.plusDays(2)
// 결과 : 2019-11-14T12:32:22.000003333

더 다양한 메소드 사용방법은 아래 표를 참고하세요

리턴 타입 메소드(매개변수) 설명
java.time.LocalDateTime plusYears()
java.time.LocalDateTime plusMonths()
java.time.LocalDateTime plusWeeks()
java.time.LocalDateTime plusDays()
java.time.LocalDateTime plusHours()
java.time.LocalDateTime plusMinutes()
java.time.LocalDateTime plusSeconds()
java.time.LocalDateTime plusNanos() 밀리초

 

LocalDateTime 날짜 비교 , 시간 비교

LocalDateTime startDateTime = LocalDateTime.now();  
// 결과 : 2021-11-12T12:32:22.000003332
LocalDateTime endDateTime = LocalDateTime.of(2021, 11, 12,12, 32,22,3333);
// 결과 : 2021-11-12T12:32:22.000003333

// startDateTime이 endDateTime 보다 이전 날짜 인지 비교
startDateTime.isBefore(endDateTime);    
// 결과 : true

// 동일 날짜인지 비교
startDateTime.isEqual(endDateTime);
// 결과 : false

// startDateTime이 endDateTime 보다 이후 날짜인지 비교
startDateTime.isAfter(endDateTime); 
// 결과 : false
LocalTime startTime = LocalTime.now();  
// 결과 : 12:52:35
LocalTime endTime = LocalTime.of(12, 59, 59);
// 결과 : 12:59:59

// startTime이 endTime 보다 이전 시간 인지 비교
startTime.isBefore(endTime);    
// 결과 : true

// startTime이 endTime 보다 이후 시간 인지 비교
startTime.isAfter(endTime); 
// 결과 : false

날짜 차이 계산

LocalDate startDate = LocalDate.now(); 
// 결과 : 2022-11-12
LocalDate endDate = LocalDate.of(2022,12,13);
// 결과 : 2022-12-13

Period period = Period.between(startDate, endDate);

period.getYears();      // 0년
period.getMonths();     // 1개월
period.getDays();       // 1일 차이

날짜 포맷

LocalDateTime now = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy년 M월 d일 a h시 m분");
String nowString = now.format(dateTimeFormatter);   
// 결과 : 2022년 11월 12일 오후 7시 2분

LocalDateTime now2 = LocalDateTime.now();  
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
// 결과 : 2022-11-12 07:26:12

날짜 변환

//LocalDate -> String
LocalDate.of(2020, 12, 12).format(DateTimeFormatter.BASIC_ISO_DATE);

//LocalDate - > String
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

//LocalDate -> java.sql.Date
Date.valueOf(LocalDate.of(2022, 12, 27));

//LocalDateTime -> java.util.Date
Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());

//LocalDateTime -> java.sql.Timestamp
Timestamp.valueOf(LocalDateTime.now());

//String -> LocalDate
LocalDate.parse("1995-05-09");
LocalDate.parse("20191224", DateTimeFormatter.BASIC_ISO_DATE);

//String -> LocalDateTime
LocalDateTime.parse("2019-12-25T10:15:30");
LocalDateTime.parse("2019-12-25 12:30:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

//java.util.Date -> LocalDateTime
LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault());

//LocalDateTime -> LocalDate
LocalDate.from(LocalDateTime.now());

//LocalDate -> LocalDateTime
LocalDate.now().atTime(2, 30);

인터뷰 면접 문제 풀면서 가끔씩 마주하게되는 해당 월 마지막 날짜 찾기

String targetDate = "2020-02-02";

YearMonth targetYearMonth = YearMonth.from(LocalDate.parse(targetDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")));

//해당 월의 일 수(int)
System.out.println(targetYearMonth.lengthOfMonth()); // 29

//해당 월의 마지막 날(LocalDate)
System.out.println(targetYearMonth.atEndOfMonth()); // 2020-02-29

해당 주차의 날짜 찾기

final long calendarWeek = 34; //34주차 입력
LocalDate desiredDate = LocalDate.now()
            .with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, calendarWeek)
            .with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
//결과 : 2020-08-17 
//DayOfWeek.MONDAY = 해당 주차에 월요일

문자열 날짜 타입 변환시 예외사항

String date = "2022-11-12 12:30:54"
LocalDateTime localdatetime = LocalDateTime.parse(date);
// 결과 : java.time.format.DateTimeParseException

String date = "2022-11-12T 12:30:54";
LocalDateTime localdatetime = LocalDateTime.parse(date);
// 결과 : parse 성공

Rest API Response 처리시 LocalDateTime LocalDate 표기 방법

public final class DateTimeConstant {
    private DateTimeConstant() {}

    public static final String DEFAULT_ZONE = "Asia/Seoul";
    public static final String DEFAULT_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_DATE = "yyyy-MM-dd";
}
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "샘플 Response")
public class SampleResponse {

    @Schema(description = "일련번호", example = "89998121")
    private long index;

    @Schema(description = "샘플정보")
    private SampleInformation sampleInformation;

    @Schema(description = "리스트", example = "[\"sampleAAA\", \"sampleBBB\"]")
    @Builder.Default
    private List<String> mockStrings = Collections.emptyList();

    @Schema(description = "리스트", example = "[\"100\", \"200\"]")
    @Builder.Default
    private List<Integer> mockNumbers = Collections.emptyList();

    @Schema(description = "생성일 날짜", example = "2022-08-08", type = "string")
    //@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeConstant.DEFAULT_DATE, timezone = DateTimeConstant.DEFAULT_ZONE)
    private LocalDate regDate;

    @Schema(description = "생성일 날짜시간", example = "2022-11-11 11:39:58", type = "string")
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeConstant.DEFAULT_PATTERN, timezone = DateTimeConstant.DEFAULT_ZONE)
    private LocalDateTime regDateTime;


}

Json으로 Return 하기위한 Response에서 날짜에 대한 타입을 Json으로 전달할때 

한줄로 표기된 문자열로 전달하고싶은데 처리가 되지 않은경우에 Json 포맷 처리하는 방법에 대해서 정리

{
	"pageIndex": 1,
	"pageRowSize": 10,
	"totalCount": 1,
	"collection": [{
		"index": 1,
		"sampleInformation": {
			"price": 9872,
			"title": "테스트샘플제목입니다.",
			"userId": "sampleUser01"
		},
		"mockStrings": [
			"aa",
			"bb"
		],
		"mockNumbers": [
			100,
			200
		],
		"regDate": [
			2022,
			9,
			7
		],
		"regDateTime": "2022-09-07 09:20:13"
	}]
}

 

@JsonFormat 사용 안했을경우 

LocalDate regDate는 Json Payload   regDate 표기된 Json을 보면 아래처럼 배열형태로 표기됨

    @Schema(description = "생성일 날짜", example = "2022-08-08", type = "string")
    private LocalDate regDate;
"regDate": [
    2022,
    9,
    7
],

 

@JsonFormat 를 사용한 LocaDateTime regDateTime 의 경우 

@Schema(description = "생성일 날짜시간", example = "2022-11-11 11:39:58", type = "string")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeConstant.DEFAULT_PATTERN, timezone = DateTimeConstant.DEFAULT_ZONE)
private LocalDateTime regDateTime;

배열이 아닌 Key : Value 형태 문자열로 표기됨 

	"regDateTime": "2022-09-07 09:20:13"

 

날짜 처리를 위해서 검색하시는 분들을 위해서

이렇게 모아서 정리해 봅니다.