[[painless-datetime]] === Using Datetime in Painless ==== Datetime API Datetimes in Painless use the standard Java libraries and are available through the Painless <>. Most of the classes from the following Java packages are available to use in Painless scripts: * <> * <> * <> * <> * <> ==== Datetime Representation Datetimes in Painless are most commonly represented as a <>, a <>, or a <>. long:: represents a datetime as the number of milliseconds or nanoseconds since epoch (1970-01-01T00:00:00Z) String:: represents a datetime as a sequence of characters defined by a well-known standard such as https://en.wikipedia.org/wiki/ISO_8601[ISO 8601] or defined by the source of input in a custom way ZonedDateTime:: a <> (object) that contains an internal representation of a datetime and provides numerous <> for modification and comparison. 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 long or String representation of a datetime to a ZonedDateTime representation, modify or compare the ZonedDateTime representation, and then switch it back to a long or String representation for storage or as a returned result. ==== Datetime Parsing and Formatting Datetime parsing is a switch from a String representation to a ZonedDateTime representation, and datetime formatting is a switch from a ZonedDateTime representation to a String representation. A <> is a <> (object) that defines the allowed sequence of characters for a String representation of a datetime. Datetime parsing and formatting often requires a DateTimeFormatter. For more information about how to use a DateTimeFormatter see the {java11-javadoc}/java.base/java/time/format/DateTimeFormatter.html[Java documentation]. ===== Datetime Parsing Examples * parse from milliseconds + [source,Painless] ---- String milliSinceEpochString = "434931330000"; long milliSinceEpoch = Long.parseLong(milliSinceEpochString); Instant instant = Instant.ofEpochMilli(milliSinceEpoch); ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, ZoneId.of('Z')); ---- + * parse from ISO 8601 + [source,Painless] ---- String datetime = '1983-10-13T22:15:30Z'; ZonedDateTime zdt = ZonedDateTime.parse(datetime); ---- Note the parse method uses ISO 8601 by default. + * parse from RFC 1123 + [source,Painless] ---- String datetime = 'Thu, 13 Oct 1983 22:15:30 GMT'; ZonedDateTime zdt = ZonedDateTime.parse(datetime, DateTimeFormatter.RFC_1123_DATE_TIME); ---- Note the use of a built-in DateTimeFormatter. + * parse from a custom format + [source,Painless] ---- String datetime = 'custom y 1983 m 10 d 13 22:15:30 Z'; DateTimeFormatter dtf = DateTimeFormatter.ofPattern( "'custom' 'y' yyyy 'm' MM 'd' dd HH:mm:ss VV"); ZonedDateTime zdt = ZonedDateTime.parse(datetime, dtf); ---- Note the use of a custom DateTimeFormatter. ===== Datetime Formatting Examples * format to a String (ISO 8601) + [source,Painless] ---- ZonedDateTime zdt = ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z')); String datetime = zdt.format(DateTimeFormatter.ISO_INSTANT); ---- Note the use of a built-in DateTimeFormatter. + * format to a String (custom) + [source,Painless] ---- ZonedDateTime zdt = ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z')); DateTimeFormatter dtf = DateTimeFormatter.ofPattern( "'date:' yyyy/MM/dd 'time:' HH:mm:ss"); String datetime = zdt.format(dtf); ---- Note the use of a custom DateTimeFormatter. ==== Datetime Conversion Datetime conversion is a switch from a long representation to a ZonedDateTime representation and vice versa. ===== Datetime Conversion Examples * convert from milliseconds + [source,Painless] ---- long milliSinceEpoch = 434931330000L; Instant instant = Instant.ofEpochMilli(milliSinceEpoch); ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, ZoneId.of('Z')); ---- + * convert to milliseconds + [source,Painless] ----- ZonedDateTime zdt = ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z')); long milliSinceEpoch = zdt.toInstant().toEpochMilli(); ----- ==== Datetime Pieces Use the ZonedDateTime <> to create a new ZonedDateTime from pieces (year, month, day, hour, minute, second, nano, time zone). Use ZonedDateTime <> to extract pieces from a ZonedDateTime. ===== Datetime Pieces Examples * create a ZonedDateTime from pieces + [source,Painless] ---- int year = 1983; int month = 10; int day = 13; int hour = 22; int minutes = 15; int seconds = 30; int nanos = 0; ZonedDateTime zdt = ZonedDateTime.of( year, month, day, hour, minutes, seconds, nanos, ZoneId.of('Z')); ---- + * extract pieces from a ZonedDateTime + [source,Painless] ---- ZonedDateTime zdt = ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 100, ZoneId.of(tz)); int year = zdt.getYear(); int month = zdt.getMonthValue(); int day = zdt.getDayOfMonth(); int hour = zdt.getHour(); int minutes = zdt.getMinute(); int seconds = zdt.getSecond(); int nanos = zdt.getNano(); ---- ==== Datetime Modification Use either a long or a ZonedDateTime to do datetime modification such as adding several seconds to a datetime or subtracting several days from a datetime. Use standard <> to modify a long representation of a datetime. Use ZonedDateTime <> to modify a ZonedDateTime representation of a datetime. Note most modification methods for a ZonedDateTime return a new instance for assignment or immediate use. ===== Datetime Modification Examples * Subtract three seconds from milliseconds + [source,Painless] ---- long milliSinceEpoch = 434931330000L; milliSinceEpoch = milliSinceEpoch - 1000L*3L; ---- + * Add three days to a datetime + [source,Painless] ---- ZonedDateTime zdt = ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z')); ZonedDateTime updatedZdt = zdt.plusDays(3); ---- + * Subtract 125 minutes from a datetime + [source,Painless] ---- ZonedDateTime zdt = ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z')); ZonedDateTime updatedZdt = zdt.minusMinutes(125); ---- + * Set the year on a datetime + [source,Painless] ---- ZonedDateTime zdt = ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z')); ZonedDateTime updatedZdt = zdt.withYear(1976); ---- ==== Elapsed Time Use either two longs or two ZonedDateTimes to calculate an elapsed time (difference) between two datetimes. Use <> to calculate an elapsed time between two longs of the same time unit such as milliseconds. For more complex datetimes. use <> to calculate the difference between two ZonedDateTimes. ===== Elapsed Time Examples * Elapsed time for two millisecond datetimes + [source,Painless] ---- long startTimestamp = 434931327000L; long endTimestamp = 434931330000L; long differenceInMillis = endTimestamp - startTimestamp; ---- + * Elapsed time in milliseconds for two datetimes + [source,Painless] ---- ZonedDateTime zdt1 = ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 11000000, ZoneId.of('Z')); ZonedDateTime zdt2 = ZonedDateTime.of(1983, 10, 13, 22, 15, 35, 0, ZoneId.of('Z')); long differenceInMillis = ChronoUnit.MILLIS.between(zdt1, zdt2); ---- + * Elapsed time in days for two datetimes + [source,Painless] ---- ZonedDateTime zdt1 = ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 11000000, ZoneId.of('Z')); ZonedDateTime zdt2 = ZonedDateTime.of(1983, 10, 17, 22, 15, 35, 0, ZoneId.of('Z')); long differenceInDays = ChronoUnit.DAYS.between(zdt1, zdt2); ---- ==== Datetime Comparison Use either two longs or two ZonedDateTimes to do a datetime comparison. Use standard <> to compare two longs of the same time unit such as milliseconds. For more complex datetimes, use ZonedDateTime <> to compare two ZonedDateTimes. ===== Datetime Comparison Examples * Comparison of two millisecond datetimes + [source,Painless] ---- long timestamp1 = 434931327000L; long timestamp2 = 434931330000L; if (timestamp1 > timestamp2) { // handle condition } ---- + * Before comparision of two datetimes + [source,Painless] ---- ZonedDateTime zdt1 = ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z')); ZonedDateTime zdt2 = ZonedDateTime.of(1983, 10, 17, 22, 15, 35, 0, ZoneId.of('Z')); if (zdt1.isBefore(zdt2)) { // handle condition } ---- + * After comparision of two datetimes + [source,Painless] ---- ZonedDateTime zdt1 = ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z')); ZonedDateTime zdt2 = ZonedDateTime.of(1983, 10, 17, 22, 15, 35, 0, ZoneId.of('Z')); if (zdt1.isAfter(zdt2)) { // handle condition } ----