I want to display a stored date (timezone is UTC) formatted with the user's timezone (may vary per each user and is stored in profile).
The solution I came up with is the following one and I want to know if this is the best way to do it, or if there is another, maybe simpler solution.
Timezone set to UTC with:
-Duser.timezone=UTC
Controller, Freemarker-Template, HandlerInterceptor:
Controller:
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping
public String dateTest(Model model){
final Date date = new Date();
model.addAttribute("formattedDate", new SimpleDateFormat("hh:mm:ss").format(date));
model.addAttribute("date", date);
return "test";
}
}
Freemarker-Template:
<#setting time_zone="${currentTimeZone}">
UTC Time: ${formattedDate}<br/>
Localized time for timezone <i>${currentTimeZone}</i>: ${date?time}
HandlerInterceptor:
public class TimezoneHandlerInterceptor extends HandlerInterceptorAdapter{
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
//Only for testing, in production something like:
//final String currentUserTimezone = userService.getCurrentUser().getTimezoneId();
final String currentUserTimezone = "Europe/Berlin";
modelAndView.addObject("currentTimeZone", currentUserTimezone);
}
}
Output:
UTC Time: 08:03:53
Localized time for timezone Europe/Berlin: 09:03:53
So is there a more standard or even out of the box way to achieve the same result? Thanks for your help.
Since you print the same date twice, only rendered differently (different time zone), it's probably just a presentation (MVC View) issue, and as such it should not be solved in the Model. Instead, you could do something like this is the template:
<#import "/lib/utils.ftl" as u>
...
UTC Time: ${u.utcTime(date)}<br/>
Localized time for timezone <i>${currentTimeZone}</i>: ${date?time}
utcTime
should be defined inside utils.ftl
like <#assign u = "com.something.freemarker.UtcTimeMethod"?new()>
, where com.something.freemarker.UtcTimeMethod
is a TemplateMethodModelEx
implementation. There are other ways of doing this, like u
is maybe a shared variable defined in the FreeMarker configuration, etc. The point is, that you need to print the UTC time doesn't affect the model.
As of the <#setting time_zone=currentTimeZone>
part (note that there's no need for ${...}
there), surely it depends on the web application framework, but the nice solution would be if you set the time zone (like based on the visitor's locale) before the template is called. FreeMarker supports that, via Template.createProcessingEnvironment
(see JavaDoc), but maybe Spring MVC doesn't.
Also, a Date
object always store the date-time in UTC. You don't need to set the time zone for that with -D
.
No, that looks good. I don't recommend relying on user.timezone for your string formatting, since eventually someone will start your webapp with the wrong timezone; instead, you can use
DateFormat formatter = new SimpleDateFormat("hh:mm:ss");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
Incidentally, have you seen CodeReview? This question is equally appropriate for both sites, given then way you've phrased it.
You can override FreeMarkerView like that
public static class YourFreemarkerView extends FreeMarkerView {
@Override
protected void processTemplate(Template template, SimpleHash model, HttpServletResponse response)
throws IOException, TemplateException {
HttpRequestHashModel httpRequestHashModel = (HttpRequestHashModel)model.get(FreemarkerServlet.KEY_REQUEST);
Environment env = template.createProcessingEnvironment(model, response.getWriter(), null);
env.setLocale(RequestContextUtils.getLocale(httpRequestHashModel.getRequest()));
env.setTimeZone(RequestContextUtils.getTimeZone(httpRequestHashModel.getRequest()));
env.process();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With