소스: java-src/intermediate/08_java_time (BusinessDays, Main). 출력이 매번 같도록 now() 는 한 줄만 쓰고 나머지는 고정 날짜입니다.
cd java-src/intermediate/08_java_time
javac -encoding UTF-8 *.java && java -Dstdout.encoding=UTF-8 MainLocalDate d = LocalDate.of(2026, 9, 9);
LocalTime t = LocalTime.of(9, 30);
LocalDateTime dt = LocalDateTime.of(d, t);
ZonedDateTime z = dt.atZone(ZoneId.of("Asia/Seoul"));
Instant i = z.toInstant();LocalDate 2026-09-09 | LocalTime 09:30 | LocalDateTime 2026-09-09T09:30
ZonedDateTime 2026-09-09T09:30+09:00[Asia/Seoul] | Instant 2026-09-09T00:30:00Z | epoch ms 1788913800000
YearMonth 2026-09 (월 단위 정산 키) | DayOfWeek WEDNESDAY | 올해 252번째 날같은 순간이 LocalDateTime 에서는 09:30, Instant 에서는 00:30Z 입니다. Z 는 UTC 표시입니다.
LocalDate d = LocalDate.of(2026, 1, 31);
d.plusDays(1); // 반환값을 버림 → d 는 그대로
LocalDate next = d.plusMonths(1); // 2월 28일
System.out.println(next.plusMonths(1)); // 3월 28일: 월말이 사라졌다
System.out.println(YearMonth.from(d).plusMonths(2).atEndOfMonth()); // 3월 31일: YearMonth 로 옮기면 유지d.plusDays(1) 호출 후 d = 2026-01-31 ← 그대로. 반환값을 받아야 한다
1월 31일 + 1개월 = 2026-02-28 ← 2월 31일이 없으니 말일로 당김 (예외 아님)
그 결과 + 1개월 = 2026-03-28 ← 3월 28일. 31→28→28: 월말이 '유실' 된다
월말 유지하려면 YearMonth 로: 2026-03-31
이달 말일 2026-01-31 | 다음 달 첫 월요일 2026-02-02
윤년 2028-02-29 + 1년 = 2029-02-28 | 2026 윤년? falseBusinessDays biz = new BusinessDays(Set.of(LocalDate.of(2026, 10, 3), LocalDate.of(2026, 10, 9))); // 개천절, 한글날
YearMonth sep = YearMonth.of(2026, 9);
BusinessDays.Period p = BusinessDays.monthPeriod(sep); // 9/1 ~ 9/30
LocalDate payDay = biz.settlementPayDay(sep); // 10/10 토요일 → 10/12 월요일
LocalDate fri = LocalDate.of(2026, 10, 8);
biz.addBusinessDays(fri, 1); // 9(한글날)·10·11(주말) 건너 12일9월 정산 기간: 2026-09-01 ~ 2026-09-30 (30일)
9월 정산 지급일(익월 10일, 영업일 보정): 2026-10-12 MONDAY
2026-10-08(THURSDAY) + 1영업일 = 2026-10-12 ← 9일 한글날·10~11일 주말을 건너뜀
2026-10-08 + 3영업일 = 2026-10-14 | -3영업일 = 2026-10-05
10/1 ~ 10/15 영업일 수: 10
분기: 2026-09 은 3분기, 분기 시작월 2026-0710월 8일 목요일의 "다음 영업일" 이 12일 월요일입니다. 달력으로는 하루 뒤지만 영업일로는 나흘 뒤입니다. 이체 예정일을 이렇게 잡지 않으면 은행 휴일에 이체가 실패합니다.
만 나이: 35세 (P35Y8M15D = 35년 8개월 15일)
총 일수: 13042일 | 총 개월 수: 428개월
배치 소요: PT30M = 30분 | 마감 D-day: 113일 남음
자정 넘김 주의: 23:50→00:20 을 시각만 빼면 PT-23H-30M (음수). 날짜를 포함해 계산해야 한다P35Y8M15D, PT30M 은 ISO 8601 기간 표기입니다. 로그에 이 형태가 찍히면 Period/Duration 의 toString 입니다.
DateTimeFormatter compact = DateTimeFormatter.ofPattern("yyyyMMdd");
dt.format(DateTimeFormatter.ofPattern("YYYY-MM-dd")); // 대문자 Y: 주 기준 연도
LocalDate.parse("20260231", compact); // SMART: 2월 28일로 조정
LocalDate.parse("20260231", DateTimeFormatter.ofPattern("uuuuMMdd").withResolverStyle(ResolverStyle.STRICT)); // 예외기본 toString(ISO): 2026-12-31T09:05:07 | yyyyMMdd: 20261231 | 사람용: 2026-12-31 09:05:07
YYYY(대문자) 함정: 2027-12-31 ← 주 기준 연도. 12월 31일이 2027년으로 찍힌다. 항상 소문자 yyyy
hh 는 12시간제: 09:05 (HH 는 09:05)
파싱: 2026-09-09 | ISO 는 포매터 없이 2026-09-09
ISO 형식이 아니면 예외: Text '2026-9-9' could not be parsed at index 5
없는 날짜 20260231 파싱: 2026-02-28 ← 예외 없이 2월 28일로 조정(기본 SMART). 엄격히 하려면 STRICT + uuuu
STRICT 파싱: Text '20260231' could not be parsed: Invalid date 'FEBRUARY 31'이 레슨을 만들며 20260231 파싱이 예외를 낼 것으로 예상하고 코드를 짰는데 그냥 통과했습니다. 기본 해석이 SMART 라는 것을 실행으로 확인한 사례이고, 사용자 입력 날짜를 검증하는 코드라면 STRICT 가 아니면 잘못된 날짜가 조용히 저장됩니다.
UTC 2026-09-09T00:30:00Z = 서울 2026-09-09T09:30 = 뉴욕 2026-09-08T20:30
LocalDateTime 2026-09-09T09:30 을 서울로 해석하면 2026-09-09T00:30:00Z, UTC 로 해석하면 2026-09-09T09:30:00Z ← 9시간 차이. 어느 쪽인지 코드에 명시해야 한다
DST: 뉴욕 01:30 + 1시간 = 03:30 (02:30 은 존재하지 않는 시각) | 한국은 DST 없음
서버 기본 시간대: Asia/Seoul ← 클라우드·컨테이너는 UTC 인 경우가 많아 LocalDateTime.now() 가 9시간 어긋난다. ZoneId 를 명시한 now(SEOUL) 을 쓴다
같은 순간 비교: false(equals: 시간대까지 비교) vs true(isEqual: 순간만 비교)Timestamp ts = Timestamp.valueOf(dt); ts.toLocalDateTime();
java.sql.Date sd = java.sql.Date.valueOf(ld); sd.toLocalDate();
legacyDate.toInstant().atZone(SEOUL).toLocalDateTime();
Instant.ofEpochSecond(1_788_931_828L); // JWT expLocalDateTime → Timestamp 2026-09-09 14:05:30.123 → 다시 2026-09-09T14:05:30.123
LocalDate → java.sql.Date 2026-09-09 → 다시 2026-09-09 (Oracle DATE 는 초까지 담으므로 시각이 필요하면 LocalDateTime)
java.util.Date → 2026-09-09T14:30:28 (레거시 API 는 toInstant() 로 건너온다)
epoch 초 1788931828 = 2026-09-09T05:30:28Z = 서울 2026-09-09T14:30:28 (JWT exp 가 이 형식)