feat(content-ranking): 랭킹 주간 기간 정책을 추가한다
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.content.ranking.domain
|
||||||
|
|
||||||
|
import java.time.DayOfWeek
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.ZonedDateTime
|
||||||
|
import java.time.temporal.TemporalAdjusters
|
||||||
|
|
||||||
|
class AudioRankingPeriodPolicy {
|
||||||
|
fun resolveLastCompletedWeek(now: ZonedDateTime): AudioRankingPeriod {
|
||||||
|
val nowKst = now.withZoneSameInstant(KST_ZONE)
|
||||||
|
val thisWeekMonday = nowKst.toLocalDate()
|
||||||
|
.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
|
||||||
|
.atStartOfDay()
|
||||||
|
return AudioRankingPeriod(
|
||||||
|
startInclusiveKst = thisWeekMonday.minusWeeks(1),
|
||||||
|
endExclusiveKst = thisWeekMonday
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toUtcRange(period: AudioRankingPeriod): AudioRankingUtcRange {
|
||||||
|
return AudioRankingUtcRange(
|
||||||
|
startInclusiveUtc = period.startInclusiveKst.atZone(KST_ZONE).withZoneSameInstant(UTC_ZONE).toLocalDateTime(),
|
||||||
|
endExclusiveUtc = period.endExclusiveKst.atZone(KST_ZONE).withZoneSameInstant(UTC_ZONE).toLocalDateTime()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val KST_ZONE: ZoneId = ZoneId.of("Asia/Seoul")
|
||||||
|
private val UTC_ZONE: ZoneId = ZoneId.of("UTC")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class AudioRankingPeriod(
|
||||||
|
val startInclusiveKst: LocalDateTime,
|
||||||
|
val endExclusiveKst: LocalDateTime
|
||||||
|
)
|
||||||
|
|
||||||
|
data class AudioRankingUtcRange(
|
||||||
|
val startInclusiveUtc: LocalDateTime,
|
||||||
|
val endExclusiveUtc: LocalDateTime
|
||||||
|
)
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.content.ranking.domain
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.DisplayName
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.ZonedDateTime
|
||||||
|
|
||||||
|
class AudioRankingPeriodPolicyTest {
|
||||||
|
private val policy = AudioRankingPeriodPolicy()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("임의의 수요일 KST 기준 지난 주 월요일 00시 이상 이번 주 월요일 00시 미만 기간을 산출한다")
|
||||||
|
fun shouldResolveLastCompletedWeekFromWednesdayByKstMonday() {
|
||||||
|
val now = ZonedDateTime.of(2026, 6, 10, 14, 30, 0, 0, ZoneId.of("Asia/Seoul"))
|
||||||
|
|
||||||
|
val period = policy.resolveLastCompletedWeek(now)
|
||||||
|
|
||||||
|
assertEquals(LocalDateTime.of(2026, 6, 1, 0, 0), period.startInclusiveKst)
|
||||||
|
assertEquals(LocalDateTime.of(2026, 6, 8, 0, 0), period.endExclusiveKst)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("기간 산출은 서버 timezone UTC와 무관하게 KST 기준으로 계산한다")
|
||||||
|
fun shouldResolveLastCompletedWeekIndependentOfServerTimezone() {
|
||||||
|
val now = ZonedDateTime.of(2026, 6, 8, 5, 30, 0, 0, ZoneId.of("UTC"))
|
||||||
|
|
||||||
|
val period = policy.resolveLastCompletedWeek(now)
|
||||||
|
|
||||||
|
assertEquals(LocalDateTime.of(2026, 6, 1, 0, 0), period.startInclusiveKst)
|
||||||
|
assertEquals(LocalDateTime.of(2026, 6, 8, 0, 0), period.endExclusiveKst)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("KST 기간은 DB 조회용 UTC LocalDateTime 이상/미만 조건으로 변환한다")
|
||||||
|
fun shouldConvertKstPeriodToUtcRange() {
|
||||||
|
val period = AudioRankingPeriod(
|
||||||
|
startInclusiveKst = LocalDateTime.of(2026, 6, 1, 0, 0),
|
||||||
|
endExclusiveKst = LocalDateTime.of(2026, 6, 8, 0, 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
val utcRange = policy.toUtcRange(period)
|
||||||
|
|
||||||
|
assertEquals(LocalDateTime.of(2026, 5, 31, 15, 0), utcRange.startInclusiveUtc)
|
||||||
|
assertEquals(LocalDateTime.of(2026, 6, 7, 15, 0), utcRange.endExclusiveUtc)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user