From 81f60652d8c4763b3470d148239c96bcd0c29553 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 1 Jul 2019 21:29:01 -0700 Subject: [PATCH] Add timezone documentation for Painless datetimes (#43768) --- .../painless-guide/painless-datetime.asciidoc | 61 +++++++++++++++---- .../{DateTests.java => DateTimeTests.java} | 16 ++++- 2 files changed, 63 insertions(+), 14 deletions(-) rename modules/lang-painless/src/test/java/org/elasticsearch/painless/{DateTests.java => DateTimeTests.java} (89%) diff --git a/docs/painless/painless-guide/painless-datetime.asciidoc b/docs/painless/painless-guide/painless-datetime.asciidoc index 5e98b39aaa7..6827a982f84 100644 --- a/docs/painless/painless-guide/painless-datetime.asciidoc +++ b/docs/painless/painless-guide/painless-datetime.asciidoc @@ -29,7 +29,7 @@ complex:: a datetime representation as a complex type (<>) that abstracts away internal details of how the datetime is stored and often provides utilities for modification and comparison; in Painless this is typically a -<> +<> Switching between different representations of datetimes is often necessary to achieve a script's objective(s). A typical pattern in a script is to switch a @@ -335,6 +335,43 @@ if (zdt1.isAfter(zdt2)) { } ---- +==== Datetime Zone + +Both string datetimes and complex datetimes have a timezone with a default of +`UTC`. Numeric datetimes do not have enough explicit information to +have a timezone, so `UTC` is always assumed. Use +<> (or fields) in +conjunction with a <> to change +the timezone for a complex datetime. Parse a string datetime into a complex +datetime to change the timezone, and then format the complex datetime back into +a desired string datetime. Note many complex datetimes are immutable so upon +modification a new complex datetime is created that requires +<> or immediate use. + +===== Datetime Zone Examples + +* Modify the timezone for a complex datetime ++ +[source,Painless] +---- +ZonedDateTime utc = + ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z')); +ZonedDateTime pst = utc.withZoneSameInstant(ZoneId.of('America/Los_Angeles')); +---- ++ +* Modify the timezone for a string datetime ++ +[source,Painless] +---- +String gmtString = 'Thu, 13 Oct 1983 22:15:30 GMT'; +ZonedDateTime gmtZdt = ZonedDateTime.parse(gmtString, + DateTimeFormatter.RFC_1123_DATE_TIME); <1> +ZonedDateTime pstZdt = + gmtZdt.withZoneSameInstant(ZoneId.of('America/Los_Angeles')); +String pstString = pstZdt.format(DateTimeFormatter.RFC_1123_DATE_TIME); +---- +<1> Note the use of a built-in DateTimeFormatter. + ==== Datetime Input There are several common ways datetimes are used as input for a script @@ -513,10 +550,9 @@ String output = input.format(DateTimeFormatter.ISO_INSTANT); <1> + ** Assumptions: + -*** The fields `start_datetime` and `end_datetime` may *not* exist in all -indexes as part of the query -*** The fields `start_datetime` and `end_datetime` may *not* have values in all -indexed documents +*** The fields `start` and `end` may *not* exist in all indexes as part of the +query +*** The fields `start` and `end` may *not* have values in all indexed documents + ** Mappings: + @@ -527,10 +563,10 @@ indexed documents ... "properties": { ... - "start_datetime": { + "start": { "type": "date" }, - "end_datetime": { + "end": { "type": "date" } ... @@ -544,14 +580,13 @@ indexed documents + [source,Painless] ---- -if (doc.containsKey('start_datetime') && doc.containsKey('end_datetime')) { <1> +if (doc.containsKey('start') && doc.containsKey('end')) { <1> - if (doc['start_datetime'].size() > 0 && doc['end_datetime'].size() > 0) { <2> + if (doc['start'].size() > 0 && doc['end'].size() > 0) { <2> - def startDatetime = doc['start_datetime'].value; - def endDatetime = doc['end_datetime'].value; - long differenceInMillis = - ChronoUnit.MILLIS.between(startDateTime, endDateTime); + def start = doc['start'].value; + def end = doc['end'].value; + long differenceInMillis = ChronoUnit.MILLIS.between(start, end); // handle difference in times } else { diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DateTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DateTimeTests.java similarity index 89% rename from modules/lang-painless/src/test/java/org/elasticsearch/painless/DateTests.java rename to modules/lang-painless/src/test/java/org/elasticsearch/painless/DateTimeTests.java index 58357cce3ac..38ceae74e05 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DateTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DateTimeTests.java @@ -22,7 +22,7 @@ package org.elasticsearch.painless; import java.time.ZoneId; import java.time.ZonedDateTime; -public class DateTests extends ScriptTestCase { +public class DateTimeTests extends ScriptTestCase { public void testLongToZonedDateTime() { assertEquals(ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of("Z")), exec( @@ -177,4 +177,18 @@ public class DateTests extends ScriptTestCase { "return zdt1.isAfter(zdt2);" )); } + + public void testTimeZone() { + assertEquals(ZonedDateTime.of(1983, 10, 13, 15, 15, 30, 0, ZoneId.of("America/Los_Angeles")), exec( + "ZonedDateTime utc = ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z'));" + + "return utc.withZoneSameInstant(ZoneId.of('America/Los_Angeles'));")); + + assertEquals("Thu, 13 Oct 1983 15:15:30 -0700", exec( + "String gmtString = 'Thu, 13 Oct 1983 22:15:30 GMT';" + + "ZonedDateTime gmtZdt = ZonedDateTime.parse(gmtString," + + "DateTimeFormatter.RFC_1123_DATE_TIME);" + + "ZonedDateTime pstZdt =" + + "gmtZdt.withZoneSameInstant(ZoneId.of('America/Los_Angeles'));" + + "return pstZdt.format(DateTimeFormatter.RFC_1123_DATE_TIME);")); + } }