Skip to content

Instantly share code, notes, and snippets.

@dacr
Last active May 27, 2023 06:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dacr/e3f0bada8aa2ace9955cc5ea91514504 to your computer and use it in GitHub Desktop.
Save dacr/e3f0bada8aa2ace9955cc5ea91514504 to your computer and use it in GitHub Desktop.
java8 time api usage examples. / published by https://github.com/dacr/code-examples-manager #0f91fe41-5463-4e0c-96c5-ca6a41b2b1da/8f2ae748adfa567d931791026eabe4fb6e89ff51
// summary : java8 time api usage examples.
// keywords : scala, scalatest, java8time, iso8601, cheatsheet, @testable
// publish : gist
// authors : David Crosson
// license : Apache NON-AI License Version 2.0 (https://raw.githubusercontent.com/non-ai-licenses/non-ai-licenses/main/NON-AI-APACHE2)
// id : 0f91fe41-5463-4e0c-96c5-ca6a41b2b1da
// created-on : 2020-05-31T21:54:52+02:00
// managed-by : https://github.com/dacr/code-examples-manager
// run-with : scala-cli $file
// ---------------------
//> using scala "3.3.0"
//> using dep "org.scalatest::scalatest:3.2.16"
//> using objectWrapper
// ---------------------
import org.scalatest._, flatspec._, matchers._
import java.util.{Date, Locale}
import java.time._
import java.time.format.DateTimeFormatter
import java.time.format.DateTimeFormatter.ISO_DATE_TIME
class Java8TimeTest extends AnyFlatSpec with should.Matchers {
override def suiteName="Java8TimeTest"
"java8 time" should "produce ISO-8601 default string format" in {
val dateString = new Date().toInstant.toString
info(dateString)
// regex coming from https://rgxdb.com/r/526K7G5W
dateString should fullyMatch regex """^(?:[\+-]?\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24\:?00)(?:[\.,]\d+(?!:))?)?(?:\2[0-5]\d(?:[\.,]\d+)?)?(?:[zZ]|(?:[\+-])(?:[01]\d|2[0-3]):?(?:[0-5]\d)?)?)?)?$"""
}
it should "support optional parts in date parsing" in {
val dateFormatPattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS]X"
val dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormatPattern)
OffsetDateTime.parse("2020-10-24T08:56:36Z", dateTimeFormatter)
OffsetDateTime.parse("2020-10-24T08:56:36.294Z", dateTimeFormatter)
ZonedDateTime.parse("2020-10-24T08:56:36Z", dateTimeFormatter)
ZonedDateTime.parse("2020-10-24T08:56:36.294Z", dateTimeFormatter)
LocalDateTime.parse("2020-10-24T08:56:36Z", dateTimeFormatter)
LocalDateTime.parse("2020-10-24T08:56:36.294Z", dateTimeFormatter)
}
it should "be easy to get current datetime" in {
def nowOld(): Date = new Date()
def instantNow(): Instant = Instant.now()
def now(): OffsetDateTime = OffsetDateTime.now(ZoneId.systemDefault)
def nowUTC(): OffsetDateTime = OffsetDateTime.now(ZoneOffset.UTC)
info("nowOld="+nowOld().toString)
info("instantNow="+instantNow().toString) // ISO-8601 string
info("now="+now().toString) // ISO-8601 string
info("nowUTC="+nowUTC().toString) // ISO-8601 string
}
it should "unfortunately not be able to basically parse some ISO-8601 timezone format using default parse" ignore {
info("Hmmm in fact it has been fixed, it was not working in some older releases of the JVM, but OK with java 15")
Instant.parse("2018-04-05T07:07:10.366Z") // OK
intercept[Exception] {
Instant.parse("2018-04-05T07:07:10.366+00:00") // KO
}
}
it should "parse any variant of ISO-8601 timezone using ISO_DATE_TIME DateTimeFormatter" in {
Instant.from(ISO_DATE_TIME.parse("2018-04-05T07:07:10Z")).toString // OK
Instant.from(ISO_DATE_TIME.parse("2018-04-05T07:07:10.366Z")).toString // OK
Instant.from(ISO_DATE_TIME.parse("2018-04-05T07:07:10.366+00:00")).toString // OK
Instant.from(ISO_DATE_TIME.parse("2018-04-05T07:07:10.729433098Z")).toString // OK
}
it should "be easy to compute the distance between two dates" in {
val first = OffsetDateTime.from(ISO_DATE_TIME.parse("2018-01-01T00:00:00Z"))
val second = OffsetDateTime.from(ISO_DATE_TIME.parse("2018-01-11T00:00:00Z"))
val duration = Duration.between(first, second)
duration.toDays shouldBe 10
}
it should "be easy to compute the distance between two instants" in {
val first = OffsetDateTime.from(ISO_DATE_TIME.parse("2018-01-01T00:00:00Z")).toInstant
val second = OffsetDateTime.from(ISO_DATE_TIME.parse("2018-01-11T00:00:00Z")).toInstant
val duration = Duration.between(first, second)
duration.toDays shouldBe 10
}
it should "be easy to convert legacy datetime to java8 datetime and vice versa" in {
info("An Instant is a moment on the timeline in UTC, a count of nanoseconds since the epoch of the first moment of 1970 UTC")
val legacyDate = new Date()
val modernInstant = legacyDate.toInstant
//val modernDate = modernInstant.atZone(ZoneId.systemDefault())
val modernDate = modernInstant.atOffset(ZoneOffset.UTC)
modernDate.toInstant.toEpochMilli shouldBe legacyDate.getTime
}
it should "be easy to deal with epoch values" in {
val instantAtZoneOffset: OffsetDateTime = Instant.ofEpochMilli(0L).atOffset(ZoneOffset.UTC)
val instantAtZoneId: ZonedDateTime = Instant.ofEpochMilli(0L).atZone(ZoneId.of("UTC"))
val instantLocal:LocalDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(0L), ZoneId.of("UTC"))
info(s"toStringAtZoneOffset=$instantAtZoneOffset") // 1970-01-01T00:00Z
info(s"toStringAtZoneId=$instantAtZoneId") // 1970-01-01T00:00Z[UTC]
info(s"toStringLocal=$instantLocal") // 1970-01-01T00:00
info("formattedAtZoneOffset="+ISO_DATE_TIME.format(instantAtZoneOffset)) // 1970-01-01T00:00Z
info("formattedAtZoneId="+ISO_DATE_TIME.format(instantAtZoneId)) // 1970-01-01T00:00Z[UTC]
info("formattedAtZoneLocal="+ISO_DATE_TIME.format(instantLocal)) // 1970-01-01T00:00
info("convertedToZoneOffset="+ISO_DATE_TIME.format(instantAtZoneOffset)) // 1970-01-01T00:00:00Z
info("convertedToZoneOffset="+ISO_DATE_TIME.format(instantAtZoneId.toOffsetDateTime)) // 1970-01-01T00:00:00Z
info("convertedToZoneOffset="+ISO_DATE_TIME.format(instantLocal.atOffset(ZoneOffset.UTC))) // 1970-01-01T00:00:00Z
instantAtZoneId.toEpochSecond shouldBe instantAtZoneOffset.toEpochSecond
}
it should "be easy to parse a date without timezone" in {
val datestr = "03/18/2015 07:44:00 PM"
val dateFormat = DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss a")
val result = LocalDateTime.parse(datestr, dateFormat)
info("when the timezone is unknown, it could be setup in adhoc way")
info(result.toInstant(ZoneOffset.UTC).toString)
}
it should "be possible to parse a date and give the right timezone" in {
val datestr = "03/18/2015 07:44:00 PM"
val dateFormat = DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss a").withZone(ZoneId.of("America/Chicago"))
val result = ZonedDateTime.parse(datestr, dateFormat)
info(result.toString)
}
it should "parse month name" in {
intercept[Exception] {
DateTimeFormatter
.ofPattern("dd-MMM-yyyy HH:mm")
.withLocale(Locale.FRENCH) // added as it is mydefault locale
.parse("24-Jan-2013 15:15")
}
DateTimeFormatter.ofPattern("dd-MMM-yyyy HH:mm")
.withLocale(Locale.ENGLISH) // MANDATORY TO AVOID EXCEPTION
.withZone(ZoneId.of("Europe/Paris")) // MANDATORY TO AVOID EXCEPTION
.parse("24-Jan-2013 15:15")
val dateFormat =
DateTimeFormatter
.ofPattern("dd-MMM-yyyy HH:mm")
.withLocale(Locale.ENGLISH)
.withZone(ZoneId.of("Europe/Paris"))
ZonedDateTime.parse("24-Jan-2013 15:15", dateFormat)
}
it should "recognize weekend days" in {
val weekday1 = Instant.from(ISO_DATE_TIME.parse("2020-03-02T10:42:42.042Z"))
val weekday2 = Instant.from(ISO_DATE_TIME.parse("2020-03-06T10:42:42.042Z"))
val weday1 = Instant.from(ISO_DATE_TIME.parse("2020-03-07T10:42:42.042Z"))
val weday2 = Instant.from(ISO_DATE_TIME.parse("2020-03-08T10:42:42.042Z"))
def isWeekEnd(instant: Instant):Boolean = { // Classical occidental WE
val day = instant.atZone(ZoneId.systemDefault()).getDayOfWeek
day == DayOfWeek.SATURDAY || day == DayOfWeek.SUNDAY
}
isWeekEnd(weekday1) shouldBe false
isWeekEnd(weekday2) shouldBe false
isWeekEnd(weday1) shouldBe true
isWeekEnd(weday2) shouldBe true
}
it should "be easy to get a DateTime from a LocalDate" in {
info("but of course only once you've provided some time information")
val csvLocale = Locale.FRENCH
val csvDateFormat = DateTimeFormatter.ofPattern("dd/MM/yyyy", csvLocale)
val dateTime =
LocalDate
.parse("22/01/2042", csvDateFormat)
.atTime(12, 42, 24)
.atZone(ZoneId.of("UTC"))
.toOffsetDateTime
dateTime.toString shouldBe "2042-01-22T12:42:24Z"
}
}
org.scalatest.tools.Runner.main(Array("-oDF", "-s", classOf[Java8TimeTest].getName))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment