diff --git a/src/main/java/repit/repit_api_server/domain/userdata/interview/dto/request/SaveInterviewRequest.java b/src/main/java/repit/repit_api_server/domain/userdata/interview/dto/request/SaveInterviewRequest.java index 3510dddc..2faadb50 100644 --- a/src/main/java/repit/repit_api_server/domain/userdata/interview/dto/request/SaveInterviewRequest.java +++ b/src/main/java/repit/repit_api_server/domain/userdata/interview/dto/request/SaveInterviewRequest.java @@ -75,6 +75,7 @@ public static class Answer { private Long questionId; private Integer responseTime; private String answerContent; + // 채팅 서버의 시각이라 UTC다. 시간대 없이 오므로 저장할 때 이 서버 시간대로 옮긴다. private LocalDateTime answerCreatedAt; } } diff --git a/src/main/java/repit/repit_api_server/domain/userdata/interview/service/InterviewService.java b/src/main/java/repit/repit_api_server/domain/userdata/interview/service/InterviewService.java index 337d5544..2ed9344d 100644 --- a/src/main/java/repit/repit_api_server/domain/userdata/interview/service/InterviewService.java +++ b/src/main/java/repit/repit_api_server/domain/userdata/interview/service/InterviewService.java @@ -37,6 +37,8 @@ import repit.repit_api_server.global.exception.BusinessException; import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; @@ -432,6 +434,19 @@ private LocalDateTime orNow(LocalDateTime createdAt) { return createdAt == null ? LocalDateTime.now() : createdAt; } + /** + * 채팅 서버가 찍은 시각을 이 서버의 시각으로 옮긴다. + * + *

채팅 서버는 UTC 컨테이너에서 시간대 없이 LocalDateTime.now()를 보낸다. 그대로 저장하면 이 서버가 UTC가 + * 아닐 때(로컬 KST) 답변만 이 서버가 찍은 질문 시각보다 9시간 이르게 남는다. + */ + // ponytail: 채팅 서버가 UTC라고 가정한다. 다른 시간대에서 돌리면 어긋나므로, 채팅 서버가 오프셋을 실어 보내면 그 값을 쓴다. + private LocalDateTime fromChatClock(LocalDateTime chatTime) { + return chatTime == null ? null : chatTime.atOffset(ZoneOffset.UTC) + .atZoneSameInstant(ZoneId.systemDefault()) + .toLocalDateTime(); + } + /** * 질문 의도. 채점은 이 값 하나를 기준으로 이뤄진다. * @@ -474,7 +489,7 @@ private void saveAnswers(InterviewEntity interview, List savedAnswers() { assertThat(answers).extracting(AnswerEntity::getQuestionId).containsExactly(901L, 902L); assertThat(answers).extracting(AnswerEntity::getUserId).containsOnly(7L); assertThat(answers.get(0).getContent()).isEqualTo("스레드가 I/O 대기에 묶였습니다."); - assertThat(answers.get(0).getCreatedAt()) - .isEqualTo(LocalDateTime.parse("2026-08-18T01:01:30")); + } + + @Test + void 채팅_서버의_UTC_답변_시각을_이_서버_시간대로_옮긴다() { + // CI는 UTC라 그대로 두면 옮기지 않아도 통과한다. 로컬처럼 KST에서 돌려 본다. + TimeZone original = TimeZone.getDefault(); + TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul")); + try { + service.saveInterview(request()); + + assertThat(savedAnswers().get(0).getCreatedAt()) + .isEqualTo(LocalDateTime.parse("2026-08-18T10:01:30")); + } finally { + TimeZone.setDefault(original); + } } @Test