Skip to content

Commit

Permalink
Merge pull request #128 from softeerbootcamp4th/fix/115-keep-timezone
Browse files Browse the repository at this point in the history
[fix] LocalDateTime에 의한 타임존 문제 해결(#115)
  • Loading branch information
blaxsior authored Aug 22, 2024
2 parents 642d475 + e6c5c0f commit bc48c1b
Show file tree
Hide file tree
Showing 36 changed files with 186 additions and 177 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package hyundai.softeer.orange.comment.dto;

import hyundai.softeer.orange.comment.entity.Comment;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.time.Instant;

@NoArgsConstructor
@Builder
Expand All @@ -16,10 +15,10 @@ public class ResponseCommentDto {
private Long id;
private String content;
private String userName;
private LocalDateTime createdAt;
private Instant createdAt;

// CommentRepository에서 Projection으로 ResponseCommentDto를 생성할 때 사용, 추후 더 나은 방법으로 수정 필요
public ResponseCommentDto(Long id, String content, String userName, LocalDateTime createdAt) {
public ResponseCommentDto(Long id, String content, String userName, Instant createdAt) {
this.id = id;
this.content = content;
this.userName = userName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;
import java.time.Instant;

@Table(name="comment")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Entity
@EntityListeners(AuditingEntityListener.class)
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand All @@ -23,7 +25,7 @@ public class Comment {
private String content;

@CreatedDate
private LocalDateTime createdAt;
private Instant createdAt;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="event_frame_id")
Expand All @@ -41,7 +43,6 @@ public static Comment of(String content, EventFrame eventFrame, EventUser eventU
comment.content = content;
comment.eventFrame = eventFrame;
comment.eventUser = eventUser;
comment.createdAt = LocalDateTime.now(); // FIXME: 현재 테스트 시 자동 생성되지 않고 있음
comment.isPositive = isPositive;
return comment;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.*;
import java.util.List;

@RequiredArgsConstructor
Expand Down Expand Up @@ -64,8 +62,8 @@ public Boolean createComment(String userId, String eventFrameId, CreateCommentDt

// 오늘의 시작과 끝 시각 계산
LocalDate today = LocalDate.now();
LocalDateTime startOfDay = today.atStartOfDay();
LocalDateTime endOfDay = today.atTime(LocalTime.MAX);
Instant startOfDay = today.atStartOfDay().atZone(ZoneOffset.systemDefault()).toInstant();
Instant endOfDay = today.atTime(LocalTime.MAX).atZone(ZoneOffset.systemDefault()).toInstant();

// 오늘 유저가 인터렉션에 참여하지 않았다면 예외처리
boolean participated = participationInfoRepository.existsByEventUserAndDrawEventAndDateBetween(eventUser, drawEvent, startOfDay, endOfDay);
Expand All @@ -77,7 +75,6 @@ public Boolean createComment(String userId, String eventFrameId, CreateCommentDt
}

boolean isPositive = commentValidator.analyzeComment(dto.getContent());

Comment comment = Comment.of(dto.getContent(), eventFrame, eventUser, isPositive);
commentRepository.save(comment);
log.info("created comment: {}", comment.getId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Date;

public class DateUtil {
public static Date localDateTimeToDate(LocalDateTime localDateTime) {
Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
Instant instant = localDateTime.atZone(ZoneOffset.systemDefault()).toInstant();

return Date.from(instant);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -50,7 +50,7 @@ public void fetchToEventEntity(EventMetadata metadata, EventDto eventDto) {
/**
* 이벤트의 시간을 검증하는 함수
*/
protected void validateEventTimes(List<FcfsEventDto> dtos, LocalDateTime startTime, LocalDateTime endTime) {
protected void validateEventTimes(List<FcfsEventDto> dtos, Instant startTime, Instant endTime) {
// 비어 있으면 안됨
if (dtos == null || dtos.isEmpty()) throw new EventException(ErrorCode.INVALID_JSON);
// 시작 순서대로 정렬
Expand All @@ -64,8 +64,8 @@ protected void validateEventTimes(List<FcfsEventDto> dtos, LocalDateTime startTi

// 시작 시간으로 정렬했으므로, 다음 시간대와 겹치지 않는다면 이후 시간대와는 절대 겹치지 않는다. O(N)
for(int idx = 0; idx < dtos.size() - 1; idx++) {
LocalDateTime nowEnd = dtos.get(idx).getEndTime();
LocalDateTime nextStart = dtos.get(idx + 1).getStartTime();
Instant nowEnd = dtos.get(idx).getEndTime();
Instant nextStart = dtos.get(idx + 1).getStartTime();

if(nowEnd.isAfter(nextStart)) throw new EventException(ErrorCode.INVALID_INPUT_EVENT_TIME);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

Expand All @@ -35,10 +35,10 @@ public class EventMetadata {
private String description;

@Column
private LocalDateTime startTime;
private Instant startTime;

@Column
private LocalDateTime endTime;
private Instant endTime;

@Column
private EventType eventType;
Expand All @@ -57,19 +57,19 @@ public void updateDescription(String description) {
this.description = description;
}

public void updateStartTime(LocalDateTime startTime) {
public void updateStartTime(Instant startTime) {
this.startTime = startTime;
}

public void updateEndTime(LocalDateTime endTime) {
public void updateEndTime(Instant endTime) {
this.endTime = endTime;
}

public void updateUrl(String url) {
this.url = url;
}

public boolean isEnded(LocalDateTime now) {
public boolean isEnded(Instant now) {
return (this.status == EventStatus.COMPLETE) || endTime.isBefore(now);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;

@Component
public class EventKeyGenerator {
Expand All @@ -23,15 +25,16 @@ public String generate() {
}

public String generate(LocalDateTime now) {
LocalDateTime nextDay = now.plusDays(1).toLocalDate().atTime(0,0,5);
// UTC 기준으로 시차는 -12 ~ 12시간, 키가 48시간 유지되면 모든 지역에서 "오늘"의 키 사용 가능. 여유 시간 10초
LocalDateTime diffDay = now.plusDays(2).toLocalDate().atTime(0,0,10);

String dateInfo = formatter.format(now);
String incKey = EventConst.REDIS_KEY_PREFIX + dateInfo;

Long number = redisTemplate.opsForValue().increment(incKey);

if(number != null && number == 1)
redisTemplate.expireAt(incKey, DateUtil.localDateTimeToDate(nextDay));
redisTemplate.expireAt(incKey, DateUtil.localDateTimeToDate(diffDay));

return String.format("HD_%s_%03d", dateInfo, number);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package hyundai.softeer.orange.event.draw.dto;

import java.time.LocalDateTime;
import java.time.Instant;

public interface EventParticipationDateDto{
LocalDateTime getDate();
Instant getDate();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package hyundai.softeer.orange.event.draw.dto;

import java.time.LocalDateTime;
import java.time.Instant;
import java.util.List;

public record EventParticipationDatesDto(List<LocalDateTime> dates) {}
public record EventParticipationDatesDto(List<Instant> dates) {}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import jakarta.persistence.*;
import lombok.Getter;

import java.time.LocalDateTime;
import java.time.Instant;

@Table(name="event_participation_info")
@Getter
Expand All @@ -15,7 +15,7 @@ public class EventParticipationInfo {
private Long id;

@Column
private LocalDateTime date;
private Instant date;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="event_user_id")
Expand All @@ -25,7 +25,7 @@ public class EventParticipationInfo {
@JoinColumn(name="draw_event_id")
private DrawEvent drawEvent;

public static EventParticipationInfo of(LocalDateTime date, EventUser eventUser, DrawEvent drawEvent) {
public static EventParticipationInfo of(Instant date, EventUser eventUser, DrawEvent drawEvent) {
EventParticipationInfo participationInfo = new EventParticipationInfo();
participationInfo.date = date;
participationInfo.eventUser = eventUser;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.time.Instant;
import java.util.List;

@Repository
Expand All @@ -27,5 +27,5 @@ public interface EventParticipationInfoRepository extends JpaRepository<EventPar
"AND info.draw_event_id = :drawEventId", nativeQuery = true)
List<EventParticipationDateDto> findByEventUserId(@Param("eventUserId") String eventUserId, @Param("drawEventId") Long drawEventId);

boolean existsByEventUserAndDrawEventAndDateBetween(EventUser eventUser, DrawEvent drawEvent, @Param("from") LocalDateTime from, @Param("to") LocalDateTime to);
boolean existsByEventUserAndDrawEventAndDateBetween(EventUser eventUser, DrawEvent drawEvent, @Param("from") Instant from, @Param("to") Instant to);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.TimeUnit;

Expand Down Expand Up @@ -48,7 +48,7 @@ public void draw(String drawEventId) {
DrawEvent drawEvent = event.getDrawEvent();
if(drawEvent == null) throw new DrawEventException(ErrorCode.EVENT_NOT_FOUND);
// 이벤트 검증
validateDrawCondition(event, LocalDateTime.now());
validateDrawCondition(event, Instant.now());
String key = EventConst.IS_DRAWING(event.getEventId());
tryDraw(key);

Expand Down Expand Up @@ -96,7 +96,7 @@ private void releaseDraw(String key) {
redisTemplate.delete(key);
}

private void validateDrawCondition(EventMetadata event, LocalDateTime now) {
private void validateDrawCondition(EventMetadata event, Instant now) {
// 이벤트가 draw event 인지 검사
if (event.getEventType() != EventType.draw) throw new DrawEventException(ErrorCode.EVENT_NOT_FOUND);
// 이벤트가 종료되었는지 검사
Expand Down Expand Up @@ -125,7 +125,7 @@ public DrawEventStatusDto getDrawEventStatus(String eventId) {

DrawEventStatus status = DrawEventStatus.AVAILABLE;

LocalDateTime now = LocalDateTime.now();
Instant now = Instant.now();

// 이벤트가 종료되었는지 검사
if (!event.isEnded(now)) status = DrawEventStatus.BEFORE_END;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.*;
import java.util.List;

/**
Expand Down Expand Up @@ -59,7 +57,7 @@ public EventParticipationDatesDto getParticipationDateList(String eventId, Strin
*/
@Transactional
public void participateDaily(String eventId, String eventUserId) {
participateAtDate(eventId, eventUserId, LocalDateTime.now());
participateAtDate(eventId, eventUserId, Instant.now());
}

/**
Expand All @@ -68,7 +66,7 @@ public void participateDaily(String eventId, String eventUserId) {
* @param eventUserId 이벤트 유저의 id
* @param date 이벤트에 참여하는 날짜.
*/
protected void participateAtDate(String eventId, String eventUserId, LocalDateTime date) {
protected void participateAtDate(String eventId, String eventUserId, Instant date) {
// 이벤트가 존재하는지 검사
EventMetadata event = emRepository.findFirstByEventId(eventId)
.orElseThrow(() -> new EventException(ErrorCode.EVENT_NOT_FOUND));
Expand All @@ -83,15 +81,16 @@ protected void participateAtDate(String eventId, String eventUserId, LocalDateTi

if(!eventUser.getEventFrameId().equals(event.getEventFrameId())) throw new EventException(ErrorCode.CANNOT_PARTICIPATE);

LocalDate today = date.toLocalDate();
// TODO: 이벤트 정보를 저장할 때 타임존을 함께 저장하도록 변경. 현재는 서버 배포 환경 시간을 기반으로 동작하도록 설정
LocalDate today = LocalDate.ofInstant(date, ZoneOffset.systemDefault());

// 이벤트 기간 안에 있는지 검사
if(event.getStartTime().isAfter(date) || event.getEndTime().isBefore(date))
throw new EventException(ErrorCode.INVALID_EVENT_TIME);

// 오늘 시작 / 끝 시간
LocalDateTime startOfDay = today.atStartOfDay();
LocalDateTime endOfDay = today.atTime(LocalTime.MAX);
Instant startOfDay = today.atStartOfDay().atZone(ZoneOffset.systemDefault()).toInstant();
Instant endOfDay = today.atTime(LocalTime.MAX).atZone(ZoneOffset.systemDefault()).toInstant();;

// 오늘 참여 여부 검사
boolean alreadyParticipated = participationInfoRepository.existsByEventUserAndDrawEventAndDateBetween(eventUser, drawEvent, startOfDay, endOfDay);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package hyundai.softeer.orange.event.dto;

import hyundai.softeer.orange.event.common.enums.EventType;
import lombok.Getter;

import java.time.LocalDateTime;
import java.time.Instant;

/**
* 이벤트 리스트를 위한 정보만 담고 있는 객체
Expand All @@ -21,12 +20,12 @@ public interface BriefEventDto {
/**
* 이벤트 시작 시간
*/
LocalDateTime getStartTime();
Instant getStartTime();

/**
* 이벤트 종료 시간
*/
LocalDateTime getEndTime();
Instant getEndTime();

/**
* 이벤트의 타입
Expand Down
Loading

0 comments on commit bc48c1b

Please sign in to comment.