Skip to content

Instantly share code, notes, and snippets.

@matdziu
Created March 20, 2019 17:11
Show Gist options
  • Select an option

  • Save matdziu/496897555dfdb24f3eaa1af3dae0ad8a to your computer and use it in GitHub Desktop.

Select an option

Save matdziu/496897555dfdb24f3eaa1af3dae0ad8a to your computer and use it in GitHub Desktop.
package com
import com.TimeSpanType.FURTHER_THAN_NEXT_DAY
import com.TimeSpanType.NEXT_DAY
import com.TimeSpanType.SAME_DAY
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import java.text.SimpleDateFormat
import java.util.Locale
enum class TimeSpanType {
SAME_DAY, NEXT_DAY, FURTHER_THAN_NEXT_DAY
}
data class Configuration(val daysNumber: Int,
val uniqueTimestampsNumber: Int,
val smallestBreakInMillis: Long) {
init {
if (daysNumber <= 0 || uniqueTimestampsNumber <= 0 || smallestBreakInMillis <= 0)
throw IllegalArgumentException("Configuration parameters must be greater than 0")
}
}
data class Timestamp(val value: String) {
private val dateFormat: SimpleDateFormat by lazy {
SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
}
private val dayInMillis = 24 * 60 * 60 * 1000
fun isNewSession(previousTimestamp: Timestamp, smallestBreakInMillis: Long): Boolean {
return (toMillis() - previousTimestamp.toMillis()) >= smallestBreakInMillis
}
fun getTimeSpan(previousTimestamp: Timestamp): TimeSpanType {
val previousTimestampMillis = previousTimestamp.toMillis()
val currentTimestampMillis = toMillis()
val millisLeftToEOD = dayInMillis - previousTimestampMillis % dayInMillis
val completedPreviousDayMillis = previousTimestampMillis + millisLeftToEOD
return if ((currentTimestampMillis > completedPreviousDayMillis)
&& (currentTimestampMillis < completedPreviousDayMillis + dayInMillis))
NEXT_DAY
else if (currentTimestampMillis < completedPreviousDayMillis)
SAME_DAY
else FURTHER_THAN_NEXT_DAY
}
private fun toMillis(): Long = dateFormat.parse(value).time
}
interface OpinionValidator {
fun shouldAskOpinion(timestamps: List<Timestamp>): Boolean
}
class OpinionValidatorImpl(private val configuration: Configuration) : OpinionValidator {
override fun shouldAskOpinion(timestamps: List<Timestamp>): Boolean {
return isAtLeastUnique(configuration.uniqueTimestampsNumber, timestamps)
&& wasUsedEveryLast(configuration.daysNumber, timestamps.reversed())
}
private fun isAtLeastUnique(n: Int, timestamps: List<Timestamp>): Boolean {
val filteredTimestamps = arrayListOf<Timestamp>()
// < 0; timestamps.count() )
for (timestampIndex in 0 until timestamps.count()) {
val currentTimestamp = timestamps[timestampIndex]
if (timestampIndex == 0) filteredTimestamps.add(currentTimestamp)
else addIfNewSession(timestamps, filteredTimestamps, currentTimestamp, timestampIndex)
}
return filteredTimestamps.count() >= n
}
private fun addIfNewSession(timestamps: List<Timestamp>,
filteredTimestamps: MutableList<Timestamp>,
currentTimestamp: Timestamp,
timestampIndex: Int) {
if (timestampIndex >= 1) {
val previousTimestamp = timestamps[timestampIndex - 1]
if (currentTimestamp.isNewSession(previousTimestamp, configuration.smallestBreakInMillis)) {
filteredTimestamps.add(currentTimestamp)
}
}
}
private fun wasUsedEveryLast(numberOfDays: Int, reversedTimestamps: List<Timestamp>): Boolean {
var consecutiveDaysCounter = 1
// < 0; reversedTimestamps.count() - 1 )
for (timestampIndex in 0 until reversedTimestamps.count() - 1) {
val currentTimestamp = reversedTimestamps[timestampIndex]
consecutiveDaysCounter = increaseIfConsecutiveDay(consecutiveDaysCounter, reversedTimestamps,
currentTimestamp, timestampIndex)
if (consecutiveDaysCounter == numberOfDays) return true
}
return false
}
private fun increaseIfConsecutiveDay(currentCounter: Int,
reversedTimestamps: List<Timestamp>,
currentTimestamp: Timestamp,
timestampIndex: Int): Int {
return if (timestampIndex <= reversedTimestamps.count() - 1) {
val previousTimestamp = reversedTimestamps[timestampIndex + 1]
val timeSpanType = currentTimestamp.getTimeSpan(previousTimestamp)
when (timeSpanType) {
NEXT_DAY -> currentCounter + 1
SAME_DAY -> currentCounter
FURTHER_THAN_NEXT_DAY -> currentCounter
}
} else 0
}
}
class Test {
@Test
fun basicTest() {
val firstList = listOf(
"2017-03-10 08:13:11",
"2017-03-10 19:01:27",
"2017-03-11 07:35:55",
"2017-03-11 16:15:11",
"2017-03-12 08:01:41",
"2017-03-12 17:19:08")
.map { Timestamp(it) }
val secondList = listOf(
"2017-03-10 18:58:11",
"2017-03-10 19:01:27",
"2017-03-11 07:35:55",
"2017-03-11 16:15:11",
"2017-03-12 08:01:41",
"2017-03-12 17:19:08")
.map { Timestamp(it) }
val thirdList = listOf(
"2017-03-08 17:11:13",
"2017-03-11 17:22:47",
"2017-03-11 19:23:51",
"2017-03-11 22:03:12",
"2017-03-12 08:32:04",
"2017-03-12 13:19:08",
"2017-03-12 17:19:08")
.map { Timestamp(it) }
val configuration = Configuration(
daysNumber = 3,
uniqueTimestampsNumber = 6,
smallestBreakInMillis = 30 * 60 * 1000)
val opinionValidator = OpinionValidatorImpl(configuration)
assertTrue(opinionValidator.shouldAskOpinion(firstList))
assertFalse(opinionValidator.shouldAskOpinion(secondList))
assertFalse(opinionValidator.shouldAskOpinion(thirdList))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment