Skip to content

Commit

Permalink
[Bug] 커피챗 예약 관련 겹치는 시간대 계산 오류를 수정한다 (#166)
Browse files Browse the repository at this point in the history
* feat: LocalDate, LocalTime, LocalDateTime 관련 대소비교 유틸성 메소드

* refactor: MentoringPeriod, Timeline 시간 대소비교 TimeUtils 메소드 활용

* style: Kotlin 파일 세미콜론 제거

* refactor: 예약 관련 겹치는 시간대 계산 로직 수정
  • Loading branch information
sjiwon authored Feb 21, 2024
1 parent ce0da0f commit 5fe916a
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ public void complete(final CoffeeChatStatus status) {
}

public boolean isRequestReservationIncludedSchedules(final Reservation target) {
return reservation.isDateTimeIncluded(target.getStart())
|| reservation.isDateTimeIncluded(target.getEnd());
return reservation.isDateTimeIncluded(target);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.koddy.server.coffeechat.domain.model;

import com.koddy.server.coffeechat.exception.CoffeeChatException;
import com.koddy.server.global.utils.TimeUtils;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.Getter;
Expand Down Expand Up @@ -40,12 +41,41 @@ private static void validateDateTimeExists(final LocalDateTime start, final Loca
}

private static void validateStartIsBeforeEnd(final LocalDateTime start, final LocalDateTime end) {
if (start.isAfter(end)) {
if (TimeUtils.isGreator(start, end)) {
throw new CoffeeChatException(RESERVATION_MUST_ALIGN);
}
}

public boolean isDateTimeIncluded(final LocalDateTime target) {
return !target.isBefore(start) && target.isBefore(end);
/**
* 1. target.end가 진행중인 시간에 포함 <br>
* -> (target.start < this.start) && (this.start < target.end <= this.end) <br><br>
* <p>
* 2. target's start, end가 진행중인 시간에 포함 <br>
* -> (this.start <= target.start <= this.end) && (this.start <= target.end <= this.end) <br><br>
* <p>
* 3. target.start가 진행중인 시간에 포함 <br>
* -> (this.start <= target.start < this.end) && (this.end < target.end) <br><br>
* <p>
* 4. target's start, end가 진행중인 시간대 전역을 커버 <br>
* -> (target.start <= this.start) && (this.end <= target.end)
*/
public boolean isDateTimeIncluded(final Reservation target) {
if (TimeUtils.isLower(target.start, this.start) && TimeUtils.isLower(this.start, target.end) && TimeUtils.isLowerOrEqual(target.end, this.end)) {
return true;
}

if (isBetween(target.start) && isBetween(target.end)) {
return true;
}

if (TimeUtils.isLowerOrEqual(this.start, target.start) && TimeUtils.isLower(target.start, this.end) && TimeUtils.isLower(this.end, target.end)) {
return true;
}

return TimeUtils.isLowerOrEqual(target.start, this.start) && TimeUtils.isLowerOrEqual(this.end, target.end);
}

private boolean isBetween(final LocalDateTime target) {
return TimeUtils.isLowerOrEqual(this.start, target) && TimeUtils.isLowerOrEqual(target, this.end);
}
}
109 changes: 109 additions & 0 deletions src/main/java/com/koddy/server/global/utils/TimeUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.koddy.server.global.utils
import com.koddy.server.global.exception.GlobalException
import com.koddy.server.global.exception.GlobalExceptionCode
import java.time.DateTimeException
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.ZoneId
Expand Down Expand Up @@ -64,4 +65,112 @@ object TimeUtils {
ZonedDateTime.of(utc, utcZoneId)
.withZoneSameInstant(kstZoneId)
.toLocalDateTime()

/**
* targetA < targetB
*/
@JvmStatic
fun isLower(
targetA: LocalDate,
targetB: LocalDate,
): Boolean = targetA < targetB

/**
* targetA <= targetB
*/
@JvmStatic
fun isLowerOrEqual(
targetA: LocalDate,
targetB: LocalDate,
): Boolean = targetA <= targetB

/**
* targetA > targetB
*/
@JvmStatic
fun isGreator(
targetA: LocalDate,
targetB: LocalDate,
): Boolean = targetA > targetB

/**
* targetA >= targetB
*/
@JvmStatic
fun isGreatorOrEqual(
targetA: LocalDate,
targetB: LocalDate,
): Boolean = targetA >= targetB

/**
* targetA < targetB
*/
@JvmStatic
fun isLower(
targetA: LocalTime,
targetB: LocalTime,
): Boolean = targetA < targetB

/**
* targetA <= targetB
*/
@JvmStatic
fun isLowerOrEqual(
targetA: LocalTime,
targetB: LocalTime,
): Boolean = targetA <= targetB

/**
* targetA > targetB
*/
@JvmStatic
fun isGreator(
targetA: LocalTime,
targetB: LocalTime,
): Boolean = targetA > targetB

/**
* targetA >= targetB
*/
@JvmStatic
fun isGreatorOrEqual(
targetA: LocalTime,
targetB: LocalTime,
): Boolean = targetA >= targetB

/**
* targetA < targetB
*/
@JvmStatic
fun isLower(
targetA: LocalDateTime,
targetB: LocalDateTime,
): Boolean = targetA < targetB

/**
* targetA <= targetB
*/
@JvmStatic
fun isLowerOrEqual(
targetA: LocalDateTime,
targetB: LocalDateTime,
): Boolean = targetA <= targetB

/**
* targetA > targetB
*/
@JvmStatic
fun isGreator(
targetA: LocalDateTime,
targetB: LocalDateTime,
): Boolean = targetA > targetB

/**
* targetA >= targetB
*/
@JvmStatic
fun isGreatorOrEqual(
targetA: LocalDateTime,
targetB: LocalDateTime,
): Boolean = targetA >= targetB
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.koddy.server.member.domain.model.mentor;

import com.koddy.server.global.utils.TimeUtils;
import com.koddy.server.member.exception.MemberException;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
Expand Down Expand Up @@ -54,13 +55,16 @@ private static void validateDateExists(final LocalDate startDate, final LocalDat
}

private static void validateStartIsBeforeEnd(final LocalDate startDate, final LocalDate endDate) {
if (startDate.isAfter(endDate)) {
if (TimeUtils.isGreator(startDate, endDate)) {
throw new MemberException(SCHEDULE_PERIOD_TIME_MUST_ALIGN);
}
}

public boolean isDateIncluded(final LocalDate date) {
return !date.isBefore(startDate) && !date.isAfter(endDate);
/**
* start <= ... <= end
*/
public boolean isDateIncluded(final LocalDate target) {
return TimeUtils.isLowerOrEqual(startDate, target) && TimeUtils.isLowerOrEqual(target, endDate);
}

public boolean allowedTimeUnit(final LocalDateTime start, final LocalDateTime end) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.koddy.server.member.domain.model.mentor;

import com.koddy.server.global.utils.TimeUtils;
import com.koddy.server.member.exception.MemberException;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
Expand Down Expand Up @@ -47,12 +48,15 @@ private static void validateTimeExists(final LocalTime startTime, final LocalTim
}

private static void validateStartIsBeforeEnd(final LocalTime startTime, final LocalTime endTime) {
if (startTime.isAfter(endTime)) {
if (TimeUtils.isGreator(startTime, endTime)) {
throw new MemberException(SCHEDULE_PERIOD_TIME_MUST_ALIGN);
}
}

public boolean isTimeIncluded(final LocalTime time) {
return !time.isBefore(startTime) && !time.isAfter(endTime);
/**
* start <= ... <= end
*/
public boolean isTimeIncluded(final LocalTime target) {
return TimeUtils.isLowerOrEqual(startTime, target) && TimeUtils.isLowerOrEqual(target, endTime);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@

import static com.koddy.server.coffeechat.exception.CoffeeChatExceptionCode.RESERVATION_INFO_MUST_EXISTS;
import static com.koddy.server.coffeechat.exception.CoffeeChatExceptionCode.RESERVATION_MUST_ALIGN;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

@DisplayName("CoffeeChat -> 도메인 [Reservation] 테스트")
Expand Down Expand Up @@ -43,4 +45,35 @@ void construct() {
assertDoesNotThrow(() -> Reservation.of(start, end));
}
}

@Test
@DisplayName("주어진 시간이 예약 시간에 포함되는지 확인한다")
void isDateTimeIncluded() {
// given
final LocalDateTime start = LocalDateTime.of(2024, 2, 27, 16, 0);
final LocalDateTime end = LocalDateTime.of(2024, 2, 27, 16, 30);
final Reservation reservation = Reservation.of(start, end);

// when
final LocalDateTime target1 = LocalDateTime.of(2024, 2, 27, 15, 30);
final LocalDateTime target2 = LocalDateTime.of(2024, 2, 27, 15, 50);
final LocalDateTime target3 = LocalDateTime.of(2024, 2, 27, 16, 0);
final LocalDateTime target4 = LocalDateTime.of(2024, 2, 27, 16, 20);
final LocalDateTime target5 = LocalDateTime.of(2024, 2, 27, 16, 30);

final boolean actual1 = reservation.isDateTimeIncluded(Reservation.of(target1, target1.plusMinutes(30)));
final boolean actual2 = reservation.isDateTimeIncluded(Reservation.of(target2, target2.plusMinutes(30)));
final boolean actual3 = reservation.isDateTimeIncluded(Reservation.of(target3, target3.plusMinutes(30)));
final boolean actual4 = reservation.isDateTimeIncluded(Reservation.of(target4, target4.plusMinutes(30)));
final boolean actual5 = reservation.isDateTimeIncluded(Reservation.of(target5, target5.plusMinutes(30)));

// then
assertAll(
() -> assertThat(actual1).isFalse(),
() -> assertThat(actual2).isTrue(),
() -> assertThat(actual3).isTrue(),
() -> assertThat(actual4).isTrue(),
() -> assertThat(actual5).isFalse()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -249,14 +249,14 @@ void success() {

// when - then
final LocalDateTime target1 = LocalDateTime.of(2024, 2, 6, 17, 0);
final LocalDateTime target2 = LocalDateTime.of(2024, 2, 6, 17, 29);
final LocalDateTime target3 = LocalDateTime.of(2024, 2, 6, 20, 0);
final LocalDateTime target2 = LocalDateTime.of(2024, 2, 6, 17, 30);
final LocalDateTime target3 = LocalDateTime.of(2024, 2, 6, 18, 30);
final LocalDateTime target4 = LocalDateTime.of(2024, 2, 7, 17, 0);
final LocalDateTime target5 = LocalDateTime.of(2024, 2, 7, 17, 29);
final LocalDateTime target6 = LocalDateTime.of(2024, 2, 7, 20, 0);
final LocalDateTime target5 = LocalDateTime.of(2024, 2, 7, 17, 30);
final LocalDateTime target6 = LocalDateTime.of(2024, 2, 7, 18, 30);
final LocalDateTime target7 = LocalDateTime.of(2024, 2, 8, 17, 0);
final LocalDateTime target8 = LocalDateTime.of(2024, 2, 8, 17, 29);
final LocalDateTime target9 = LocalDateTime.of(2024, 2, 8, 20, 0);
final LocalDateTime target8 = LocalDateTime.of(2024, 2, 8, 17, 30);
final LocalDateTime target9 = LocalDateTime.of(2024, 2, 8, 18, 30);

assertAll(
() -> assertDoesNotThrow(() -> sut.check(mentor, Reservation.of(target1, target1.plusMinutes(30)))),
Expand Down

0 comments on commit 5fe916a

Please sign in to comment.