ISO 8601 ๋ ?
ISO 8601์ ๋ ์ง์ ์๊ฐ์ ๊ด๋ จ๋ ๊ตญ์ ํ์ค์ผ๋ก์จ, ์ ์๋ ๋ฐ์ ๋ฐ๋ฅด๋ฉด ๋งค์ฃผ์ ์์์ผ์ ์์์ผ์ด ๋ฉ๋๋ค.
๋ํ, ๋งค์์ ์ฒซ ์ฃผ๋ ๊ณผ๋ฐ์ ์ด์์ ์์ผ์ด ํฌํจ๋ ์ฃผ๊ฐ ๊ธฐ์ค์ด ๋ฉ๋๋ค.
ISO 8601 ๊ธฐ์ค์ผ๋ก ์ฃผ์ฐจ ๊ณ์ฐ ์์
2024๋ 12์ ์์
- 2024๋
12์ 30์ผ, 31์ผ์ ๋ค์๊ณผ ๊ฐ์ ๊ท์น์ ๋ฐ๋ฆ
๋๋ค.
- 2025๋ 1์ 1~5์ผ(์ด 5์ผ)์ 7์ผ ์ค ๊ณผ๋ฐ์๋ฅผ ๋์ผ๋ฏ๋ก 1์ 1์ฃผ์ฐจ์ ๋๋ค
- ๋ฐ๋ผ์, 2024๋ 12์ 30์ผ, 31์ผ์ 2025๋ 1์ 1์ฃผ์ฐจ์ ํฌํจ๋ฉ๋๋ค
12์ 2์ผ ~ 12์ 8์ผ -> 12์ 1์ฃผ์ฐจ
12์ 9์ผ ~ 12์ 15์ผ -> 12์ 2์ฃผ์ฐจ
12์ 16์ผ ~ 12์ 22์ผ -> 12์ 3์ฃผ์ฐจ
12์ 23์ผ ~ 12์ 29์ผ -> 12์ 4์ฃผ์ฐจ
12์ 30์ผ ~ 1์ 5์ผ -> 1์ 1์ฃผ์ฐจ
2026๋
12์ ์์
- 2027๋ 1์์ ์ฒซ ์ฃผ๋ 1~3์ผ(์ด 3์ผ)๋ก ๊ตฌ์ฑ๋๋ฉฐ, ์ด๋ 7์ผ ์ค ๊ณผ๋ฐ์๊ฐ ๋์ง ์์ผ๋ฏ๋ก 12์ 5์ฃผ์ฐจ์ ํฌํจ๋ฉ๋๋ค.
- ๊ทธ๋์, 12์ 28์ผ ~ 1์ 3์ผ๊น์ง๋ 12์ 5์ฃผ์ฐจ์ด๋ฉฐ 1์ 4์ผ(์์์ผ)๋ถํฐ 1์ 1์ฃผ์ฐจ๊ฐ ๋ฉ๋๋ค.
ํน์ ๋ ์ง์ N์ N์ฃผ์ฐจ ๊ตฌํ๋ ๋ฐฉ๋ฒ
ISO 8601 ๊ธฐ์ค์์ ๋งค์ฃผ ์์์ผ์ด ์์์ผ, ์ผ์์ผ์ด ๋ง์ง๋ง ๋ ๋ก ๊ณ ์ ๋ฉ๋๋ค.
๊ทธ๋์, ํน์ ๋ ์ง๊ฐ ํฌํจ๋ ์ฃผ์ ์ค๊ฐ์ผ(๋ชฉ์์ผ)์ด ์ด๋ค ๋ฌ์ ์ํ๋์ง ์๋ฉด ํน์ ๋ ์ง์ ์ฃผ์ฐจ๋ฅผ ๊ตฌํ ์ ์๋ค๊ณ ์๊ฐํ์ต๋๋ค.
- ์ฃผ์ ์ค๊ฐ์ผ(๋ชฉ์์ผ)์ด ํด๋น ์์ ์ํ๋ฉด ๊ทธ ์ฃผ๋ ํด๋น ์์ ๋ง์ง๋ง ์ฃผ์ฐจ๋ก ํ๋จํฉ๋๋ค.
- ๋ฐ๋๋ก ์ค๊ฐ์ผ(๋ชฉ์์ผ)์ด ๋ค์ ์์ ์ํ๋ฉด ๊ทธ ์ฃผ๋ ๋ค์ ์์ ์ฒซ ์ฃผ์ฐจ๋ก ํ๋จํฉ๋๋ค.
๊ทธ๋์, ๋ช์ ๋ช์ฃผ์ฐจ๋ฅผ ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ๊ตฌํ์ต๋๋ค.
1. ํน์ ๋ ์ง๊ฐ ํฌํจ๋ ์ฃผ์ ์์์ผ ๊ตฌํ๊ธฐ
- TemporalAdjusters.previousOrSame()๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น ์ฃผ์ ์์์ผ(LocalDate)์ ๊ตฌํฉ๋๋ค.
2. ์ค๊ฐ์ผ(๋ชฉ์์ผ) ๊ตฌํ๊ธฐ
- ๊ตฌํ ์์์ผ์ plusDays(3)๋ฅผ ๋ํด ์ค๊ฐ์ผ(๋ชฉ์์ผ)์ ๊ณ์ฐํฉ๋๋ค.
3. ์ค๊ฐ์ผ(๋ชฉ์์ผ)์ ํด๋นํ๋ ์ ํ์ธํ๊ธฐ
- LocalDate.getMonthValue()๋ก ์ค๊ฐ์ผ์ ์์ ํ์ธํฉ๋๋ค.
4. ์ค๊ฐ์ผ์ด ISO ๊ธฐ์ค ๋ช ์ฃผ์ฐจ์ธ์ง ํ์ธ
- WeekFields.ISO.weekOfMonth()๋ฅผ ์ฌ์ฉํด ISO ๊ธฐ์ค ์ฃผ์ฐจ๋ฅผ ๊ตฌํฉ๋๋ค.
- WeekFields.ISO๋ WeekFields.of(DayOfWeek.MONDAY, 4)๋ก ๊ตฌํ๋์ด ์์ต๋๋ค.
์ ์ฒด ํ ์คํธ ์ฝ๋์ ๋๋ค.
@DisplayName("2024๋
12์ 31์ผ์ ISO ๊ธฐ์ค์ผ๋ก 1์ 1์ฃผ์ฐจ์ด๋ค.")
@Test
void ISO_๊ธฐ์ค์ผ๋ก_ํน์ ๋ ์ง์๋ํด_๋ช์_๋ช์ฃผ์ฐจ๋ฅผ_๊ตฌํ๋ค() {
// given
LocalDate target = LocalDate.of(2024, 12, 31);
LocalDate startOfWeek = target.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); // ํด๋น ์ฃผ ์์์ผ
LocalDate endOfWeek = target.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)); // ํด๋น ์ฃผ ์ผ์์ผ
LocalDate middleOfWeek = startOfWeek.plusDays(3); // ํด๋น ์ฃผ์ ์ค๊ฐ์ผ
// when
int monthValue = middleOfWeek.getMonthValue();
int isoWeekValue = middleOfWeek.get(WeekFields.ISO.weekOfMonth());
//then
Assertions.assertThat(startOfWeek).isEqualTo(LocalDate.of(2024, 12, 30));
Assertions.assertThat(endOfWeek).isEqualTo(LocalDate.of(2025, 1, 5));
Assertions.assertThat(monthValue).isEqualTo(1);
Assertions.assertThat(isoWeekValue).isEqualTo(1);
System.out.println("ํด๋น ๋ ์ง๊ฐ ํฌํจ๋ ์ฃผ์ ์์์ผ: " + startOfWeek); // 12์ 30์ผ
System.out.println("ํด๋น ๋ ์ง๊ฐ ํฌํจ๋ ์ฃผ์ ์ผ์์ผ: " + endOfWeek); // 1์ 5์ผ
System.out.println("ํด๋น ๋ ์ง์ ๋ช ์: " + monthValue); // 1์
System.out.println("ํด๋น ๋ ์ง์ ๋ช ์ฃผ์ฐจ: " + isoWeekValue); // ์ ๊ธฐ์ค์ผ๋ก 1์ฃผ์ฐจ (1~5์ ๊ฐ ์ค ํ๋)
System.out.println(target.get(WeekFields.ISO.weekOfWeekBasedYear())); // ๋
๊ธฐ์ค์ผ๋ก N์ฃผ์ฐจ (1~53์ ๊ฐ ์ค ํ๋)
}
์ด๋ฅผ ์์ฉํด์ 2024๋
11์ 16์ผ์ ๊ธฐ์ค์ผ๋ก ์ 4๊ฐ ์ฃผ์ฐจ์ ์์์ผ, ๋ง์ง๋ง์ผ, N์, N์ฃผ์ฐจ๋ฅผ ๊ตฌํด๋ณด๊ฒ ์ต๋๋ค.
@DisplayName("24๋
11์ 16์ผ ๊ธฐ์ค์ผ๋ก 4์ฃผ์ฐจ์ ์์์ผ,๋ง์ง๋ง์ผ,๋ช์,๋ช์ฃผ์ฐจ ๋ฅผ ๊ตฌํ๋ค.")
@Test
void test() {
// given
LocalDate today = LocalDate.of(2024, 11, 16);
List<WeeklyDate> weeklyDates = IntStream.rangeClosed(1, 4)
.mapToObj(i -> {
LocalDate minusDate = today.minusDays((long) i * 7);
LocalDate firstOfWeek =
minusDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
LocalDate lastOfWeek = minusDate.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
LocalDate middleOfWeek = firstOfWeek.plusDays(3);
return new WeeklyDate(
firstOfWeek,
lastOfWeek,
middleOfWeek.getMonthValue(),
middleOfWeek.get(WeekFields.ISO.weekOfMonth())
);
})
.sorted()
.collect(Collectors.toList());
for (WeeklyDate weeklyDate : weeklyDates) {
System.out.println("weeklyDate = " + weeklyDate);
}
}
static class WeeklyDate implements Comparable<WeeklyDate> {
LocalDate startDate;
LocalDate endDate;
int monthValue;
int weekNumber;
public WeeklyDate(LocalDate startDate, LocalDate endDate, int monthValue, int weekNumber) {
this.startDate = startDate;
this.endDate = endDate;
this.monthValue = monthValue;
this.weekNumber = weekNumber;
}
@Override
public int compareTo(@NotNull WeeklyTest.WeeklyDate o) {
return startDate.compareTo(o.startDate);
}
@Override
public String toString() {
return "WeeklyDate{" +
"startDate=" + startDate +
", endDate=" + endDate +
", month=" + month +
", weekNumber=" + weekNumber +
'}';
}
}
์์์ผ์ ์์์ผ, ๋ง์ง๋ง์ผ์ ์ผ์์ผ, ๋ช์ ๋ช์ฃผ์ฐจ์ ํด๋นํ๋ ๊ฐ์ด ์ด 4๊ฐ๊ฐ ์ ๋์จ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
WeekFields ํด๋์ค ์ค๋ช
WeekFields ํด๋์ค๋ Java 8์์ ๋์
๋ ํด๋์ค์ด๋ฉฐ, ํน์ ๋ฌธํ๊ถ ๋๋ ํ์ค์ ๋ฐ๋ผ ์ฃผ(week)๋ฅผ ์ ์ํ๊ณ ๊ด๋ฆฌํ๊ธฐ ์ํ ํด๋์ค์
๋๋ค.
- ์ง์ญํ๋ ์ฃผ ์ ์(Localization)
- ์๋ก ๋ค๋ฅธ ๋ฌธํ๊ถ์์๋ ์ฃผ์ ์์ ์์ผ๊ณผ ์ฒซ ๋ฒ์งธ ์ฃผ๋ฅผ ์ ์ํ๋ ๋ฐฉ์์ด ๋ค๋ฆ ๋๋ค.
- WeekFields๋ ์ด๋ฌํ ์ฐจ์ด๋ฅผ ๋ฐ์ํ์ฌ ์ฃผ์ ์ ์๋ฅผ ๋ง์ถค ์ค์ ํ ์ ์๋๋ก ํฉ๋๋ค.
- WeekFields.of(new Locale("ko", "KR") ์ ์ฌ์ฉํ๋ฉด ํ๊ตญ ๋ฌธํ๊ถ์์์ ์์ ์์ผ๊ณผ ์ฒซ๋ฒ์งธ ์ฃผ ๊ท์น์ ๋ฐ๋ฆ ๋๋ค.
- ko ์ KR ๊ฐ์ด ์ ์ํ๊ณ ์ถ์ ์ธ์ด์ ๋๋ผ๋ฅผ ์๊ณ ์ถ๋ค๋ฉด Locale[] locales = Locale.getAvailableLocales(); ์ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
- Thread-Safe ๋ฐ Immutable
- ์ด ํด๋์ค๋ ๋ถ๋ณ(Immutable)์ด๋ฉฐ, ๋ค์ค ์ค๋ ๋ ํ๊ฒฝ์์๋ ์์ ํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ISO-8601 ํ์ค๊ณผ์ ํธํ์ฑ
- ISO-8601 ํ์ค์์ ์ฃผ์ ์์ ์์ผ์ ์์์ผ์ด๋ฉฐ, ์ฒซ ๋ฒ์งธ ์ฃผ๋ ์ต์ 4์ผ์ ํฌํจํด์ผ ํ๋ค๋ ๊ธฐ์ค์ ๋ฐ๋ฆ ๋๋ค.
- WeekFields๋ฅผ ํตํด ์ด๋ฌํ ๊ธฐ์ค๋ฟ๋ง ์๋๋ผ ๋ค๋ฅธ ๊ธฐ์ค๋ ์ ์ํ ์ ์์ต๋๋ค.
- ์๋ฅผ ๋ค์ด, ์ผ์์ผ๋ถํฐ ์ต์ 3์ผ์ ํฌํจํ๋ฉด ์ ํจํ ์ฃผ๋ผ๊ณ ๋ณด๊ณ ์ถ๋ค๋ฉด WeekFields.of(DayOfWeek.SUNDAY, 3) ๋ก ์์ฑํ๋ค์ LocalDate.get() ์ ํ๋ผ๋ฏธํฐ์ ์ฃผ์ ํ๋ฉด ๋ฉ๋๋ค.
TemporalAdjuster ํด๋์ค ์ค๋ช
TemporalAdjuster๋ Java8์ java.time ํจํค์ง์ ์ํ๋ฉฐ, ๋ ์ง์ ์๊ฐ์ ์กฐ์ ํ๊ธฐ ์ํ ์ธํฐํ์ด์ค์
๋๋ค.
์ด๋ฅผ ํตํด Temporal ๊ฐ์ฒด(์: LocalDate, LocalDateTime)๋ฅผ ๋ค์ํ ๋ฐฉ์์ผ๋ก ์์ ํ ์ ์์ต๋๋ค.
- previous(DayOfWeek): ํญ์ ์ด์ ์ฃผ์ ์์ผ์ด ํ์ํ ๊ฒฝ์ฐ ์ฌ์ฉํฉ๋๋ค.
- ํ์ฌ ๋ ์ง๊ฐ ํ ์์ผ์ผ ๋, previous(DayOfWeek.SATURDAY) ๋ฅผ ํ๋ฉด ์ ๋ฒ ์ฃผ ํ ์์ผ์ ๋ฐํํฉ๋๋ค.
- previsoueOrSame(DayOfWeek): ํ์ฌ ๋ ์ง๊ฐ ์กฐ๊ฑด์ ๋ง์กฑํ ๊ฒฝ์ฐ ์ด๋ฅผ ๊ทธ๋๋ก ์ ์งํ๊ณ , ๊ทธ๋ ์ง ์์ผ๋ฉด ์ด์ ์์ผ๋ก ์ด๋ํฉ๋๋ค.
- ex) ํ์ฌ ๋ ์ง๊ฐ ํ ์์ผ์ผ ๋, previouseOrSame(DayOfWeek.SATURDAY) ๋ฅผ ํ๋ฉด ํ์ฌ ๋ ์ง๋ฅผ ๋ฐํํฉ๋๋ค.
- ํ์ฌ ๋ ์ง๊ฐ ํ ์์ผ ์ผ๋, previousOrSame(DayOfWeek.MONDAY) ๋ฅผ ํ๋ฉด ํด๋น ์ฃผ์ ์์์ผ์ ๋ฐํํฉ๋๋ค.
- firstDayOfMonth(): ๋ฌ์ ์ฒซ ๋ฒ์งธ ๋
- lastDayOfMonth(): ๋ฌ์ ๋ง์ง๋ง ๋
- next(DayOfWeek): ๋ค์ ํน์ ์์ผ
- firstInMonth(DayOfWeek): ์ ๋ด ํน์ ์์ผ์ ์ฒซ ๋ฒ์งธ ๋
๋ง์น๋ฉฐ.
๋น์ฌ์ด๋ ํ๋ก์ ํธ๋ฅผ ํ๋ฉด์ ํด๋น ๋ ์ง๊ฐ ๋ช์ ๋ช์ฃผ์ฐจ์ด๋ฉฐ, ์์์ผ~์ผ์์ผ๊น์ง์ ๋ ์ง๋ฅผ ๊ตฌํ๋ ์๊ตฌ์ฌํญ์ด ์์ด์ ๋ ์งAPI๋ฅผ ์ฌ์ฉํด๋ดค๋๋ฐ์.
์ฒ์์๋ Baeldung ์ ์๋ฃ๋ง์ ์ฐธ๊ณ ํ๋ค๊ฐ ํ
์คํธ ์ฝ๋๋ฅผ ๋๋ ค๋ณด๋ Baeldung์์ ๋์จ ์ฝ๋๊ฐ ISO ๊ธฐ์ค์ด ์๋์ ์์์ต๋๋ค.
์ญ์ ์ฒ์ ์ฌ์ฉํด๋ณด๋ API๋ ํ
์คํธ ์ฝ๋๋ก ํ์ธํ๋ ์์ธ๋ ํ์์ธ๊ฒ ๊ฐ์ต๋๋ค.
์ฌ๋ฌ๋ถ๋ ๋ ์ง์ ์๊ฐ ๊ด๋ จ ๋ก์ง์ ๋ค๋ฃฐ ๋ ๊ผญ ํ
์คํธ ์ฝ๋๋ก ํ์ธํด๋ณด์๊ธธ ์ถ์ฒ๋๋ฆฌ๋ฉฐ ๋ง๋ฌด๋ฆฌ ํ๊ฒ ์ต๋๋ค!
์ฐธ๊ณ
- Baeldung ์ Getting the Week Number From Any Date
- stackoverflow ์ How to get dates of a week (I know week number)?