app/logic/Date.scala (94 lines of code) (raw):
package logic
import models.{DisplayMode, Festive, Normal, Spooky}
import java.time.ZoneOffset.UTC
import java.time._
import java.time.format.DateTimeFormatter
import scala.util.Try
object Date {
private val simpleDateFormatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(UTC)
private val dateTimeFormatter =
DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").withZone(UTC)
private val timeFormatter =
DateTimeFormatter.ofPattern("HH:mm:ss").withZone(UTC)
private val friendlyDateFormatter =
DateTimeFormatter.ofPattern("d MMMM, yyyy").withZone(UTC)
def formatDateTime(instant: Instant): String =
dateTimeFormatter.format(instant)
def formatTime(instant: Instant): String =
timeFormatter.format(instant)
def formatDate(instant: Instant): String = {
friendlyDateFormatter.format(instant)
}
def rawDate(instant: Instant): String = {
simpleDateFormatter.format(instant)
}
def isoDateString(instant: Instant): String = {
DateTimeFormatter.ISO_INSTANT.format(instant)
}
def formatInterval(
instant: Instant,
comparison: Instant = Instant.now()
): String = {
formatDuration(Duration.between(comparison, instant))
}
def formatDuration(duration: Duration): String = {
Seq(
duration.toHours.toInt -> "hour",
duration.toMinutesPart -> "minute",
duration.toSecondsPart -> "second"
).collect {
case (1, unit) => s"1 $unit"
case (value, unit) if value > 1 => s"$value ${unit}s"
}.mkString(", ")
}
def firstDayOfWeek(instant: Instant): Instant =
instant
.atZone(UTC)
.`with`(DayOfWeek.MONDAY)
.toInstant
def weekAround(instant: Instant): (Instant, Instant) = {
val start = firstDayOfWeek(instant)
(start, start.plus(Duration.ofDays(7)))
}
private[logic] def isInAuditRange(instant: Instant): Boolean = {
val auditStart =
ZonedDateTime.of(2015, 11, 1, 23, 59, 59, 0, UTC).toInstant
instant.isAfter(auditStart) &&
instant.isBefore(Instant.now())
}
def prevNextAuditWeeks(
instant: Instant
): (Option[Instant], Option[Instant]) = {
val week = firstDayOfWeek(instant)
(
Some(week.minus(Duration.ofDays(7))).filter(isInAuditRange),
Some(week.plus(Duration.ofDays(7))).filter(isInAuditRange)
)
}
/** Parses a date string in the format "yyyy-MM-dd" and if it's valid returns
* the instant at the start of that date in UTC.
*/
def parseUtcDateStr(dateStr: String): Option[Instant] = {
Try {
val localDate = LocalDate.parse(dateStr, simpleDateFormatter)
localDate.atStartOfDay(UTC).toInstant
}.toOption
}
def todayUtc: Instant = {
LocalDate
.now(UTC)
.atStartOfDay(UTC)
.toInstant
}
def maxDuration(d1: Duration, d2: Duration): Duration = {
if (d1.compareTo(d2) > 0) d1 else d2
}
def minDuration(d1: Duration, d2: Duration): Duration = {
if (d1.compareTo(d2) < 0) d1 else d2
}
def displayMode(today: ZonedDateTime): DisplayMode = {
if (today.getDayOfMonth == 31 && today.getMonthValue == 10) Spooky
else if (
(20 to 26).contains(today.getDayOfMonth) && today.getMonthValue == 12
) Festive
else Normal
}
}