Frage

How can I print date and time is specified timezone with Thymeleaf? Something like:

<span th:text="${#dates.format(myDate, 'yyyy-MM-dd HH:mm', 'PST')}">2010-01-01 16:30</span>
War es hilfreich?

Lösung 2

As I was puzzled by this question, I searched extensively for possible solutions.

These are my findings: I did not found any clean function for changing timezone and displaying it like it is in jsp:

<fmt:timeZone value="US">
<fmt:formatDate value="${today}"  type="both" />
</fmt:timeZone>

Possible solution, that works would be to create calendar instance using createForTimeZone and format it, since it returns a raw calendar value, so from this:

#calendars.createForTimeZone(year, month, day, hour, minute, second, milisecond, Object timezone)

you would get something like this:

java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="PST",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=PST,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2014,MONTH=1,WEEK_OF_YEAR=14,WEEK_OF_MONTH=1,DAY_OF_MONTH=24,DAY_OF_YEAR=91,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=1,AM_PM=0,HOUR=6,HOUR_OF_DAY=7,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=-28800000,DST_OFFSET=3600000]

As you can see (you have to look carefully) it did converted time to the timezone provided.

Now, I still haven't gotten to the point where I can get it all to work fine, but if you add calendars.format in front of this, you would get it to properly show time in the given timezone. ${#calendars.format(#calendars.createForTimeZone(year, month, day, hour, minute, second, milisecond, Object timezone), 'dd-MMM-yyyy HH:mm')}

Adding "zzz" to the end of the string, always return my locale timezone. I guess there are way to work this out so it looks better, but main point for me was to find out if it was possible at all.

Examples that work:

${#dates.format(#calendars.createForTimeZone(#calendars.year(ticket.ticketDate), #calendars.month(ticket.ticketDate), #calendars.day(ticket.ticketDate), #calendars.hour(ticket.ticketDate), #calendars.minute(ticket.ticketDate),'PST'), 'yyyy-MMM-dd HH:mm')}

${#calendars.format(#calendars.createForTimeZone(#calendars.year(ticket.ticketDate), #calendars.month(ticket.ticketDate), #calendars.day(ticket.ticketDate), #calendars.hour(ticket.ticketDate), #calendars.minute(ticket.ticketDate),'CET'), 'yyyy-MMM-dd HH:mm')}

and either one would return identical results.

Here are the results when comparing same format, using PST and CET:

2014-Feb-24 16:00
2014-Feb-24 07:00

or:

2014-Mar-01 03:00
2014-Feb-28 18:00

Regards,

Andere Tipps

Another approach to the same problem may be to use your own static methods:

${T(xx.xxx.utils.DateUtils).format(myDate, 'yyyy-MM-dd HH:mm', 'CET')}

  public static String format(Date date, String pattern, String timeZone) {
    TimeZone tz = TimeZone.getTimeZone(timeZone);
    return DateFormatUtils.format(date, pattern, tz);
  }

or even directly from lang3 (does not work on GAE because of some class access restrictions in sun.util.calendar package):

<div th:with="timeZone=${T(java.util.TimeZone).getTimeZone('CET')}">
   <span th:text="${T(org.apache.commons.lang3.time.DateFormatUtils).format(myDate, 'yyyy-MM-dd HH:mm', timeZone)}"></span>
</div>

I found this answer when I wanted to format LocalDateTime to some time zone in the templates. It turned out that the purpose of LocalDateTime is to do not work with time zones at all.

However, there is also a class called ZonedDateTime which purpose is obvious. You can also use LocalDateTime#atZone which creates a new instance of local converted to the new zone.

Note that usual DateTimeFormatter ignores any time zone settings in the case of local date time but not in the case of zoned date time. So you can use usual formatters as well in the templates.

The server renders the page based on the server time, in order to get the timezone of the user from the request, the user when submitting the request should attach the timezone information in the request headers or parameters, so that the server knows the appropriate time zone to render. To do that, use javascript to get the browser's time zone.

Using Thymeleaf's #temporals doesn't provide the ability to use the constructor new Temporals(locale, zoneId).

Create your own Temporals temporals = new Temporals(LocaleContextHolder.getLocale(), zone) (somewhere, session bean, or so - zone should probably come from your user's preferences), and put it available in the controller (eg. as "temporalsZone").

Then use it in the UI: th:text="${temporalsZone.format(value, pattern, #locale)}"> and enjoy the full support of #temporals.

If you add org.thymeleaf.extras:thymeleaf-extras-java8time as a dependency, you get the #temporals object to help format types like:

  • Instant
  • LocalDateTime
  • ZonedDateTime
  • etc

If you want to format java.util.Date you can use #dates instead.

The methods you're looking for are #dates.format or #temporals.format. You can specify a Locale as the third argument. The general syntax is #temporals.format(<temporal object>, <pattern>, <optional locale>)

Examples:

  • th:text="${#temporals.format(myDate, 'dd-MM-yyyy', new java.util.Locale('en'))}"
  • th:text="${#temporals.format(myDate, 'dd-MM-yyyy', @java.util.Locale@ENGLISH)}"

Note that this is true even if you're working with Kotlin Spring Boot. The syntax in the Thymeleaf template isn't Java, it's an OGNL Expression.

https://commons.apache.org/proper/commons-ognl/language-guide.html

I'll quote the useful syntax used here:

#variable
Context variable reference

@class@method(args)
Static method reference

@class@field
Static field reference

new class(args)
Constructor call

One other option is to specify the Locale in the Thymeleaf context, if you just want to override the default system Locale. I've included a Kotlin snippet of how that might work:

val context = Context() // org.thymeleaf.Context
context.locale = Locale.ENGLISH
context.setVariable("x", 0)

templateEngine.process("classpath:template.html", context)

Then you can simply use th:text="${#temporals.format(datum.timestamp, 'E MMM dd yyyy')} without the explicit Locale argument.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top