Skip to content

Instantly share code, notes, and snippets.

@danslapman
Created June 20, 2018 11:02
Show Gist options
  • Save danslapman/6d98ea29596b57715907fae2ce9cc1fd to your computer and use it in GitHub Desktop.
Save danslapman/6d98ea29596b57715907fae2ce9cc1fd to your computer and use it in GitHub Desktop.
JSR310 custom formatters
import java.time._
import java.time.format.{DateTimeFormatter, DateTimeFormatterBuilder}
import java.time.temporal.{ChronoField, TemporalAccessor}
import java.{time => jt}
import scala.util.Try
trait ZonedParser {
protected val formatter: DateTimeFormatter
def apply(date: String): ZonedDateTime = ZonedDateTime.parse(date, formatter)
def unapply(date: String): Option[ZonedDateTime] = Try {this(date)}.toOption
def unapply(date: Option[String]): Option[ZonedDateTime] = date flatMap unapply
}
case class ZonedDateTimeParser(pattern: String) extends ZonedParser {
protected override val formatter: DateTimeFormatter = new DateTimeFormatterBuilder()
.appendPattern(pattern)
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.toFormatter
.withZone(JSR310.systemDefaultZone)
}
trait OffsetParser {
protected val formatter: DateTimeFormatter
def apply(date: String): OffsetDateTime = OffsetDateTime.parse(date, formatter)
def unapply(date: String): Option[OffsetDateTime] = Try {this(date)}.toOption
def unapply(date: Option[String]): Option[OffsetDateTime] = date flatMap unapply
}
trait OffsetParserWithDefaults extends OffsetParser {
protected val localTime: LocalTime
protected val offset: ZoneOffset
override def apply(date: String): OffsetDateTime = formatter.parseBest(
date,
(temporal: TemporalAccessor) => OffsetDateTime.from(temporal),
(temporal: TemporalAccessor) => LocalDateTime.from(temporal),
(temporal: TemporalAccessor) => LocalDate.from(temporal)) match {
case odt: OffsetDateTime => odt
case ldt: LocalDateTime => OffsetDateTime.of(ldt, offset)
case ld: LocalDate => OffsetDateTime.of(ld, localTime, offset)
}
}
case class OffsetDateTimeParser(
pattern: String,
protected val localTime: LocalTime = LocalTime.MIDNIGHT,
protected val offset: ZoneOffset = ZoneOffset.UTC) extends OffsetParserWithDefaults {
protected override val formatter: DateTimeFormatter = new DateTimeFormatterBuilder()
.appendPattern(pattern)
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.toFormatter
}
object ISO8601Zoned extends ZonedParser {
override protected val formatter: DateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME.withZone(systemDefaultZone)
}
object ISO8601Offset extends OffsetParserWithDefaults {
override protected val localTime: LocalTime = LocalTime.MIDNIGHT
override protected val offset: ZoneOffset = ZoneOffset.UTC
override protected val formatter: DateTimeFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.optionalStart().appendLiteral("T").append(DateTimeFormatter.ISO_LOCAL_TIME).optionalEnd()
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
.optionalStart().appendOffset("+HHMM", "+0000").optionalEnd()
.optionalStart().appendOffset("+HH", "Z").optionalEnd()
.optionalStart().appendLiteral('[').parseCaseSensitive().appendZoneRegionId().appendLiteral(']')
.toFormatter()
}
val ISO8601UTCLocal: DateTimeFormatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneOffset.UTC)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment