Hello

Apache poi getDateCellValue() 엑셀과 다른 경우 본문

java

Apache poi getDateCellValue() 엑셀과 다른 경우

nari0_0 2023. 2. 7. 13:10
728x90

엑셀에서 날짜를 읽어 db 저장 후 조회 시 날짜값이 다르게 들어갔다는 이슈를 전달 받았다.

디버깅을 해보니 엑셀은 아래와 같은 시간인데 실제로 읽은 데이터는 다르게 읽혀 굉장히 당황 스러웠다.

구글링을 해보니 엑셀이 밀리초 없이 날짜 시간 값을 표시하면 내부적 으로 초로 반올림해 날짜를 표시한다는 글이 있어 확인을 해보니 getDateCellValue() 내부적으로 getNumbericCellValue()를 호출해 Date 객체를 만드는데 이 때 millisecond 값이 995로 들어가서 59초로 만들어지게 된다. 그래서 14:20을 기대했으나 14:19:59라는 결과를 얻게 된다.

getDateCellValue() 메소드 로직

그래서 자바에서도 반올림을 해 처리를 해야 하는 것을 알게 되었다.

 

getDateCellValue() 에서 DateUtil.getJavaDate() 메소드를 호출해 날짜를 생성한다. DateUtil.class docs를 확인해 보니 반올림을 지원하는 메소드가 있어 해당 메소드를 사용했다.

 

엑셀이 1904 기간을 사용하는지 아래 메소드를 사용해 알 수 있다. 

boolean date1904 = workbook.isDate1904();

그리고, getDateCellValue()는 기본적으로 반올림을 하지 않기 때문에 반올림이 필요 없는 경우 getDateCellValue()를 사용해도 충분 할 것 이다. 반올림이 필요할 때 위 메소드를 호출해 roundSeconds자리에 true 값을 넣어 사용하면 된다.

 

반올림 지원하는 메소드

DateUtil.getJavaDate(row.getCell(3).getNumericCellValue(), date1904, TimeZone.getDefault(), true);

 위 날짜 변환 시 기대값(14:20)으로 변환 되는 것을 확인했다.

반올림 된 데이터

 

반올림을 어디서 처리하는 것인지 궁금해 getJavaDate() 호출 스택을 따라가 보았는데 setCalendar() 내부에서 roundSeconds가 true 일 때 milliSecond에 500을 더해 반올림 하는 것을 확인할 수 있었다.

setCalendar() 메소드 중 일부

끝-

참고 :
https://stackoverflow.com/questions/56842654/apache-poi-date-parsing-one-second-off

https://poi.apache.org/apidocs/dev/org/apache/poi/ss/usermodel/DateUtil.html

728x90