Dates.kt

  1. package com.hexagontk.core

  2. import java.time.*
  3. import java.util.Date

  4. private const val DAYS_PER_MONTH: Double = 30.4375

  5. /** GMT zone ID. */
  6. val GMT_ZONE: ZoneId by lazy { ZoneId.of("GMT") }

  7. /**
  8.  * Return the date time in a given time zone for a local date time.
  9.  *
  10.  * @receiver Local date time to be moved to another time zone.
  11.  * @param zoneId Id of the target zone of the passed local date time.
  12.  * @return Received date time at the given [zoneId].
  13.  */
  14. fun LocalDateTime.withZone(zoneId: ZoneId = Platform.timeZone.toZoneId()): ZonedDateTime =
  15.     ZonedDateTime.of(this, zoneId)

  16. /**
  17.  * Convert a zoned date time to a date.
  18.  *
  19.  * @receiver Zoned date time to be converted to a date.
  20.  * @return Date representation of the given zoned date time.
  21.  */
  22. fun ZonedDateTime.toDate(): Date =
  23.     Date.from(this.toInstant())

  24. /**
  25.  * Convert a local date time to a date.
  26.  *
  27.  * @receiver Local date time to be converted to a date.
  28.  * @return Date representation of the given local date time.
  29.  */
  30. fun LocalDateTime.toDate(): Date =
  31.     this.atZone(Platform.timeZone.toZoneId()).toDate()

  32. /**
  33.  * Convert a local date to a date.
  34.  *
  35.  * @receiver Local date to be converted to a date.
  36.  * @return Date representation of the given local date.
  37.  */
  38. fun LocalDate.toDate(): Date =
  39.     this.atStartOfDay(Platform.timeZone.toZoneId()).toDate()

  40. /**
  41.  * Convert a date to a local date time.
  42.  *
  43.  * @receiver Date to be converted to a local date time.
  44.  * @return Local date time representation of the given date.
  45.  */
  46. fun Date.toLocalDateTime(): LocalDateTime =
  47.     LocalDateTime.ofInstant(Instant.ofEpochMilli(this.time), ZoneId.systemDefault())

  48. /**
  49.  * Convert a date to a local date.
  50.  *
  51.  * @receiver Date to be converted to a local date.
  52.  * @return Local date representation of the given date.
  53.  */
  54. fun Date.toLocalDate(): LocalDate =
  55.     this.toLocalDateTime().toLocalDate()

  56. /**
  57.  * Calculate the aproximate number of days comprised in a time period.
  58.  *
  59.  * @receiver Period from which calculate the number of days.
  60.  * @return Aproximate number of days of the period.
  61.  */
  62. fun Period.toTotalDays(): Double =
  63.     (toTotalMonths() * DAYS_PER_MONTH) + days

  64. /**
  65.  * Parse a time period allowing a more relaxed format: with spaces or commas, lowercase characters
  66.  * and not forcing the text to start with 'P'.
  67.  *
  68.  * @param text Text to be parsed to a time period.
  69.  * @return Time period parsed from the supplied text.
  70.  */
  71. fun parsePeriod(text: String): Period =
  72.     Period.parse(formatDuration(text))

  73. /**
  74.  * Parse a time duration allowing a more relaxed format: with spaces or commas, lowercase characters
  75.  * and not forcing the text to start with 'P', however, the 'T' is still mandatory to separate date
  76.  * and time durations.
  77.  *
  78.  * @param text Text to be parsed to a time duration.
  79.  * @return Time duration parsed from the supplied text.
  80.  */
  81. fun parseDuration(text: String): Duration =
  82.     Duration.parse(formatDuration(text))

  83. private fun formatDuration(text: String): String =
  84.     text
  85.         .replace(",", "")
  86.         .replace(" ", "")
  87.         .uppercase()
  88.         .let { if (it.startsWith("P")) it else "P$it" }

  89. /**
  90.  * Parse a local date allowing only to specify the year or the year and the month. Missing month and
  91.  * day will be defaulted to january and one respectively.
  92.  *
  93.  * @param text Text to be parsed to a local date.
  94.  * @return Local date parsed from the supplied text.
  95.  */
  96. fun parseLocalDate(text: String): LocalDate =
  97.     when (text.length) {
  98.         4 -> Year.parse(text).atMonth(1).atDay(1)
  99.         7 -> YearMonth.parse(text).atDay(1)
  100.         else -> LocalDate.parse(text)
  101.     }