날짜와 시간을 다루는 부분이 의외로(?) 까다롭다는 얘길 들어서 도전해보고 싶었다.
자원해서 수정 작업에 들어갔다.
목요일보다 이전 요일에 있으면
그 주는 N월의 1주차 이다.일요일
이다.즉, 일요일부터 한 주를 시작하지만 특정 월의 첫 주를 결정짓는 것은 1일이 일 ~ 목 중에 있는지 여부이다.
월요일
이다.일요일
이다.case WEEKLY:
LocalDateTime dateTime = getWeekStartDay(dateDescription);
// 한 주의 시작일을 일요일로 설정
// 1일이 일 ~ 목요일 일 때 1일이 포함된 월의 첫 주로 설정하기 위해 최소 필요한 일수는 3일로 설정함
TemporalField weekOfMonth = WeekFields.of(DayOfWeek.SUNDAY, 3).weekOfMonth();
LocalDateTime thursday = dateTime.plusDays(4);
int dayOfMonth = thursday.getDayOfMonth();
int year = thursday.getYear();
formatter = DateTimeFormatter.ofPattern("MM월 ");
String thursdayMonth = thursday.format(formatter);
int week;
if(dayOfMonth < 6) {
week = 1;
} else {
week = thursday.get(weekOfMonth);
}
return new StringBuilder().append(year)
.append("년 ")
.append(thursdayMonth)
.append(week)
.append("주차")
.toString();
+) 참고로 ISO 8601은 WeekFields.of(DayOfWeek.MONDAY, 4)
이고 미국식은 WeekFields.of(DayOfWeek.SUNDAY, 1)
이었다.
// KST 시작일자 뽑기
public static LocalDateTime getWeekStartDay(String yyyyuu) {
int year = Integer.parseInt(yyyyuu.substring(0,4));
// 그 해의 몇 일째인지 (2023년 56일째 || 2023년 300일째)
int day = Integer.parseInt(yyyyuu.substring(4)) == 0 ? 1 : Integer.parseInt(yyyyuu.substring(4)) * 7;
LocalDate ld = LocalDate.ofYearDay(year, day);
// 월요일 == 1, 일요일 == 7
int turn = ld.getDayOfWeek().getValue() == 7 ? 0 : ld.getDayOfWeek().getValue();
// DayofWeek는 월요일이 한 주의 시작이므로 뒤집어 줌(일요일을 시작일이 되게)
return ld.minusDays(turn).atTime(0,0,0);
}
// KST 종료일자 뽑기
public static LocalDateTime getWeekEndDay(String yyyyuu) {
int year = Integer.parseInt(yyyyuu.substring(0,4));
int day = Integer.parseInt(yyyyuu.substring(4)) == 0 ? 1 : Integer.parseInt(yyyyuu.substring(4)) * 7;
LocalDate ld = LocalDate.ofYearDay(year, day);
int turn = ld.getDayOfWeek().getValue() == 7 ? 0 : ld.getDayOfWeek().getValue();
// 종료일자는 토요일이 되도록 뽑아야 하므로 plus 해줌
return ld.plusDays(6-turn).atTime(23,59, 59);
}
ld.minusDays(1).atTime(0,0,0) == 2023 05 28 00:00:00
ld.plusDate(6-1).atTime(23,59,59) == 2023 06 03 23:59:59
우리는 ES에서 조회해오고, 네트워크 이슈 등으로 ES 조회 실패할 때만 DB에서 쿼리하도록 돼 있다.
ES에서 조회할 때 시작일/종료일에 맞게 결과가 안 나오는 상태였다.
Date histogram aggregation이 Calendar intervals week (1w)로 설정
돼 있었고,
ES는 별도 설정이 없다면 월요일이 한 주의 시작
이었기 때문에 start,endDate는 의미가 없었다.
offSet : -1d
를 주니 해결됐다.다만 offSet은 주차별 조회할 때만 적용돼야 하기 때문에 아래처럼 분기문을 태웠다.
private String getOffSetData(StatisticsDateType dateType) {
// ES 조회 시, 일요일을 주의 시작점으로 잡기 위해 설정
if(StatisticsDateType.WEEKLY.equals(dateType)) {
return DateHistogramInterval.days(-1).toString();
} else {
return "0";
}
}
offSet을 적용하기 전에 calendar intervals 를 fixed intervals로 변경해보기도 하고, 주 단위를 -7d로 검색하도록 해보기도 했으나 방법이 아니었다.
+) fixed intervals 관련 공식 문서 : https://www.elastic.co/guide/en/elasticsearch/reference/7.15/search-aggregations-bucket-datehistogram-aggregation.html#fixed_intervals
ES에서 Date histogram aggregation 포함 aggregation 쪽도 공부해볼 부분이 많은 곳이라 기회가 된다면 포스팅 해보려고 한다.
2022년 12월 마지막 주로도 검색해보고, 과거 일자로 조회 해보고 다양하게 조회해봐도 이슈 없이 현재까지 정상 조회 돼서 뿌듯했다.
날짜, 특히 주차별 조회 이슈를 해결하면서 공식 문서들을 뒤져보고 공부한 게 든든한 자산이 될 것 같다.