Skip to content

Commit c435f5a

Browse files
authored
Merge pull request #25 from bpholt/DateTimeFormatter
add support for DateTimeFormatter literals
2 parents 75e19cc + 81eed16 commit c435f5a

File tree

4 files changed

+47
-3
lines changed

4 files changed

+47
-3
lines changed

build.sbt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ lazy val V = new {
99
val SCALA_3 = "3.0.2"
1010
val Scalas = Seq(SCALA_2_13, SCALA_2_12, SCALA_3)
1111
val literally = "1.0.2"
12+
val munit = "0.7.29"
1213
}
1314

1415
inThisBuild(List(
@@ -55,7 +56,8 @@ lazy val `java-time-literals` = crossProject(JSPlatform, JVMPlatform)
5556
scalaReflect ++
5657
Seq(
5758
"org.typelevel" %% "literally" % V.literally,
58-
"org.scalameta" %% "munit" % "0.7.29" % Test,
59+
"org.scalameta" %% "munit" % V.munit % Test,
60+
"org.scalameta" %% "munit-scalacheck" % V.munit % Test,
5961
)
6062
},
6163
Compile / unmanagedSourceDirectories ++= { // needed until https://github.com/portable-scala/sbt-crossproject/issues/70 is fixed

core/shared/src/main/scala-2/dev/holt/javatime/literals.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package dev.holt.javatime
33
import org.typelevel.literally.Literally
44

55
import java.time._
6+
import java.time.format.DateTimeFormatter
67
import scala.reflect.macros.blackbox
78
import scala.util.{Failure, Success, Try}
89

@@ -274,4 +275,23 @@ object literals {
274275
}
275276
}
276277

278+
implicit class dateTimeFormatter(val sc: StringContext) extends AnyVal {
279+
def dateTimeFormatter(args: Any*): DateTimeFormatter = macro DateTimeFormatterLiteral.make
280+
}
281+
282+
object DateTimeFormatterLiteral extends Literally[DateTimeFormatter] {
283+
def make(c: blackbox.Context)
284+
(args: c.Expr[Any]*): c.Expr[DateTimeFormatter] = apply(c)(args: _*)
285+
286+
override def validate(c: DateTimeFormatterLiteral.Context)
287+
(s: String): Either[String, c.Expr[DateTimeFormatter]] = {
288+
import c.universe.{Try => _, _}
289+
290+
Try(DateTimeFormatter.ofPattern(s)) match {
291+
case Failure(ex) => Left(ex.getMessage)
292+
case Success(_) => Right(c.Expr(q"java.time.format.DateTimeFormatter.ofPattern($s)"))
293+
}
294+
}
295+
}
296+
277297
}

core/shared/src/main/scala-3/dev.holt.javatime/literals.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package dev.holt.javatime
33
import org.typelevel.literally.Literally
44

55
import java.time._
6+
import java.time.format.DateTimeFormatter
67
import scala.util.{Failure, Success, Try}
78

89
//noinspection ScalaUnusedSymbol
@@ -22,6 +23,7 @@ object literals {
2223
inline def zonedDateTime(args: Any*): ZonedDateTime = ${ZonedDateTimeLiteral('ctx, 'args)}
2324
inline def zoneId(args: Any*): ZoneId = ${ZoneIdLiteral('ctx, 'args)}
2425
inline def zoneOffset(args: Any*): ZoneOffset = ${ZoneOffsetLiteral('ctx, 'args)}
26+
inline def dateTimeFormatter(args: Any*): DateTimeFormatter = ${DateTimeFormatterLiteral('ctx, 'args)}
2527
}
2628

2729
object DurationLiteral extends Literally[Duration] {
@@ -136,4 +138,12 @@ object literals {
136138
}
137139
}
138140

141+
object DateTimeFormatterLiteral extends Literally[DateTimeFormatter] {
142+
override def validate(s: String)(using Quotes) =
143+
Try(DateTimeFormatter.ofPattern(s)) match {
144+
case Failure(ex) => Left(ex.getMessage)
145+
case Success(_) => Right('{java.time.format.DateTimeFormatter.ofPattern(${Expr(s)})})
146+
}
147+
}
148+
139149
}

core/shared/src/test/scala/dev/holt/javatime/JavaTimeSuite.scala

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package dev.holt.javatime
22

33
import dev.holt.javatime.literals._
4-
import munit.FunSuite
4+
import munit.ScalaCheckSuite
5+
import org.scalacheck.Prop.forAll
56

67
import java.time._
8+
import java.time.format.DateTimeFormatter
79

8-
class JavaTimeSuite extends FunSuite {
10+
class JavaTimeSuite extends ScalaCheckSuite {
911
test("Duration interpolation should work like runtime parsing") {
1012
val expected = Duration.parse("PT20.345S")
1113
val output = duration"PT20.345S"
@@ -103,4 +105,14 @@ class JavaTimeSuite extends FunSuite {
103105

104106
assertEquals(expected, output)
105107
}
108+
109+
test("DateTimeFormatter interpolation should work like runtime parsing") {
110+
forAll { (timestamp: LocalDateTime) =>
111+
val expected = DateTimeFormatter.ofPattern("yyyy").format(timestamp)
112+
val output = dateTimeFormatter"yyyy".format(timestamp)
113+
114+
assertEquals(expected, output)
115+
}
116+
}
117+
106118
}

0 commit comments

Comments
 (0)