Last active
May 25, 2024 10:18
-
-
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/a95c0134c55377a72c5ecb1baf5f14b93272cde0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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.4.2" | |
//> 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