'How to format java.time.LocalDateTime and java.time.LocalDate with pattern?

In the following snipped the property $F is of class java.time.LocalDateTime or java.time.LocalDate.

<textField pattern="EE. dd.MM.yyyy">
    <reportElement...>
    </reportElement>
    <textFieldExpression><![CDATA[$F{theLocalDateTime}]]></textFieldExpression>
</textField>

How can I format this property with textField pattern in jasper reports?



Solution 1:[1]

To use the pattern attribute in current version of jasper-report for Date/Time object you need a java.util.Date class or one of it's subclasses.

The solution is to convert java.time.LocalDate and java.time.LocalDateTime

Converting to java.util.Date

from java.time.LocalDate

<textField pattern="EE. dd.MM.yyyy">
    <reportElement...>
    </reportElement>
    <textFieldExpression><![CDATA[java.util.Date.from($F{theLocalDate}.atStartOfDay(java.time.ZoneId.systemDefault()).toInstant())]]></textFieldExpression>
</textField>

from java.time.LocalDateTime

<textField pattern="EE. dd.MM.yyyy">
    <reportElement...>
    </reportElement>
    <textFieldExpression><![CDATA[java.util.Date.from($F{theLocalDateTime}.atZone(java.time.ZoneId.systemDefault()).toInstant())]]></textFieldExpression>
</textField>

Converting to java.sql.Timestamp

from java.time.LocalDate

<textField pattern="EE. dd.MM.yyyy">
    <reportElement...>
    </reportElement>
    <textFieldExpression><![CDATA[java.sql.Timestamp.valueOf($F{theLocalDate}.atStartOfDay())]]></textFieldExpression>
</textField>

from java.time.LocalDateTime

<textField pattern="EE. dd.MM.yyyy">
    <reportElement...>
    </reportElement>
    <textFieldExpression><![CDATA[java.sql.Timestamp.valueOf($F{theLocalDateTime})]]></textFieldExpression>
</textField>

Note: Applying pattern is always preferable solution, specially when exporting to excel since correct class will be passed to poi (hence excel will recognize column as a date and apply same formatting as in pattern)

Solution 2:[2]

As java.time module is kind of complex and verbose, I usually create some variables which holds the compiled DateTimeFormatter for further use.

I want my reports to adapt to any Locale, so I don't use string literals for formatting.

I am using the report Locale, but you can choose your Locale with java.util.Locale.forLanguageTag("en-US"), for example.

You can also change the java.time.format.FormatStyle if needed

LocalDate formatter:

    <variable name="dateFormatter" class="java.time.format.DateTimeFormatter">
        <variableExpression><![CDATA[java.time.format.DateTimeFormatter
  .ofLocalizedDate(java.time.format.FormatStyle.SHORT)
  .withLocale($P{REPORT_LOCALE})
  .withChronology(java.time.chrono.Chronology.ofLocale($P{REPORT_LOCALE}))]]></variableExpression>
    </variable>

LocalDateTime formatter:

    <variable name="dateTimeFormatter" class="java.time.format.DateTimeFormatter">
        <variableExpression><![CDATA[java.time.format.DateTimeFormatter
  .ofLocalizedDateTime(java.time.format.FormatStyle.SHORT)
  .withLocale($P{REPORT_LOCALE})
  .withChronology(java.time.chrono.Chronology.ofLocale($P{REPORT_LOCALE}))]]></variableExpression>
    </variable>

Now I can format a LocalDate field this way:

$F{localDateField}.format($V{dateFormatter})

And a LocalDateTime field this way:

$F{localDateTimeField}.format($V{dateTimeFormatter})

Solution 3:[3]

I've stumpled over the same problem and I solved it by introducing a custom function to JasperReports. So at the end it can be used as following on LocalDate, LocalTime, LocalDateTime, just anything implementing TemporalAccessor:

FORMAT_DATETIME($F{someLocalDate}, "dd.MM.yyyy")
FORMAT_DATETIME($F{someLocalDateTime}, "dd.MM.yyyy HH:mm")
FORMAT_DATETIME($F{someLocalTime}, "HH:mm")

To achieve that create following files:

Function Category. This is needed so the Expression Editor of the jasper report designer shows the function, under the set category

package org.example.jrfunctions;

import net.sf.jasperreports.functions.annotations.FunctionCategory;

@FunctionCategory()
public class LocalDateTime {
}

Class with the function(s) (more functions could be added)

package org.example.jrfunctions;

import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;

import net.sf.jasperreports.functions.annotations.Function;
import net.sf.jasperreports.functions.annotations.FunctionCategories;
import net.sf.jasperreports.functions.annotations.FunctionParameter;
import net.sf.jasperreports.functions.annotations.FunctionParameters;

@FunctionCategories({
        org.example.jrfunctions.LocalDateTime.class })
public class JRDateTimeFunctions {

    @Function("FORMAT_DATETIME")
    @FunctionParameters({
            @FunctionParameter("temporalObject"),
            @FunctionParameter("format")
            })
    public static String FORMAT_DATETIME(TemporalAccessor temporalObject, String format) {
        if (temporalObject == null) {
            return null;
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        return formatter.format(temporalObject);
    }

}

The following file needs to be in the same directory as the above two, and all the properties for every parameter needs to be set. Otherwise the jasper report designer will not show the custom functions in the expression editor:

jasperreports_messages.properties

org.example.jrfunctions.JRDateTimeFunctions.FORMAT_DATETIME.description = Formats the Temporal Object according to format
org.example.jrfunctions.JRDateTimeFunctions.FORMAT_DATETIME.name = Format Temporal Accessor (Object)
org.example.jrfunctions.JRDateTimeFunctions.FORMAT_DATETIME.temporalObject.name = Temporal Accessor
org.example.jrfunctions.JRDateTimeFunctions.FORMAT_DATETIME.temporalObject.description = Object to format
org.example.jrfunctions.JRDateTimeFunctions.FORMAT_DATETIME.format.name = Format
org.example.jrfunctions.JRDateTimeFunctions.FORMAT_DATETIME.format.description = Fromat
org.example.jrfunctions.LocalDateTime.name=Local Date & Time
org.example.jrfunctions.LocalDateTime.description=

The following file needs to be in the classpath. I put it into src/main/resources

jasperreports_extension.properties

net.sf.jasperreports.extension.registry.factory.functions=net.sf.jasperreports.functions.FunctionsRegistryFactory
net.sf.jasperreports.extension.functions.jrdatetimefunctions=org.example.jrfunctions.JRDateTimeFunctions

Now the custom function should be shown in the expression editor, and compile without any problems.

More infos:

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Community
Solution 2 Fabiano Bonin
Solution 3 RMM