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>
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>
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,
#calendars.format
and #dates.format
take by default the time zone of the server the app is run on anyway. What is created by #calendars.createForTimeZone
does not matter because it will be changed by formatting anyway. If I deploy it locally in CET
and then deploy to a heroku server which uses UTC
then the output is shifted by 2 hours in the view. At least for my application where I use instances of DateTime
of Joda. –
Cassandra -Duser.timezone=CET
to JVM. This is possible on heroku thanks to Procfile
, not sure how it looks with AWS. –
Cassandra 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>
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,
#calendars.format
and #dates.format
take by default the time zone of the server the app is run on anyway. What is created by #calendars.createForTimeZone
does not matter because it will be changed by formatting anyway. If I deploy it locally in CET
and then deploy to a heroku server which uses UTC
then the output is shifted by 2 hours in the view. At least for my application where I use instances of DateTime
of Joda. –
Cassandra -Duser.timezone=CET
to JVM. This is possible on heroku thanks to Procfile
, not sure how it looks with AWS. –
Cassandra 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
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.
© 2022 - 2024 — McMap. All rights reserved.
<td th:text="${ticket.ticketDate} ? ${#dates.format(ticket.ticketDate, 'dd/MM/yyyy zzz')} : ''">Ticket Date</td>
. Response that I get is 31/03/2014 CET... So it picks up locale. Or you want to tell Thymeleaf which locale to use? – Bartie