7

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?

Petter Friberg
  • 21,252
  • 9
  • 60
  • 109
membersound
  • 81,582
  • 193
  • 585
  • 1,120
  • 2
    With a regular formatter like shown here http://stackoverflow.com/a/15817417/1743880, but for Java 8? Would be `DateTimeFormatter.ofPattern(myPattern).format($F{thedatetime})`. – Tunaki Aug 08 '16 at 13:40
  • @Tunaki in this case the user like to use pattern that is also preferable when you export to different formats (hence correct format in excel etc), pattern can be used on java.util.Date objects, so the solution is to convert the field to such an class (or subclass) and wait for jasper-reports to update their library to also support the formatting with patterns of the LocalDateTime class – Petter Friberg Aug 08 '16 at 14:14
  • You do not want a `LocalDateTime`. The `java.sql.Timestamp` class was replaced by `java.time.Instant` or `OffsetDateTime` (with its offset set to UTC). See this Question, [*What's the difference between Instant and LocalDateTime?*](https://stackoverflow.com/q/32437550/642706). – Basil Bourque Feb 04 '19 at 00:04

3 Answers3

11

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)

Community
  • 1
  • 1
Petter Friberg
  • 21,252
  • 9
  • 60
  • 109
  • A `Timestamp` does *not* map to a `LocalDateTime`. `Timestamp` represents a moment, a specific point on the timeline. A `LocalDateTime` purposely lacks any concept of time zone or offset-from-UTC. As such it *cannot* represent a moment. It represents *potential* moments along a range of about 26-27 hours (the range of time zones around the globe). `Timestamp` is replaced by the `Instant` class, or an `OffsetDateTime` with its offset set to UTC. Hence the [`java.sql.Timestamp::toInstant`](https://docs.oracle.com/en/java/javase/11/docs/api/java.sql/java/sql/Timestamp.html#toInstant()) method. – Basil Bourque Feb 04 '19 at 00:02
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})
  • Thanks - that saved my day! I prefer this solution, because this allows string literals in text fields together with the formatted date, like `"formatted date is " + $F{localDateField}.format($V{dateFormatter})`. – RoM Aug 27 '21 at 07:15
0

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:

RMM
  • 21
  • 4