Работа с датой, как правило, является не самым приятным занятием при разработке приложения. Одной из проблем является настройка таймзоны, особенно, если данные поступают от различных клиентов с разными таймзонами.
Рассмотрим решение одной из таких проблем в JSF.
Как известно, JVM использует таймзону системы и конвертирует всю дату с использованием этой таймзоны, однако, компонент <f:convertDateTime/> по умолчанию использует таймзону GMT+00, что зачастую приводит к несовпадению даты в самом приложении и в представлении, например: если в приложении установлена таймзона GMT+03, то дата 12.01.2018 00:00:00 при отображении превратится в 11.01.2018 21:00:00. Чтобы исключить такое поведение, необходимо в файл web.xml добавить следующий параметр:
<context-param>
<param-name>javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE</param-name>
<param-value>true</param-value>
</context-param>
Это позволит нам решить проблему отображения дат не завязаных на таймзону, например дата без указания часа, но не поможет в том случае, если мы хотим отображать дату в таймзоне клиента.
Для этого решения этой задачи можно выполнить следующие действия:
- На стороне клиента, с помощью Javascript сохраняем в Cookie значение клиентской таймзоны
(function setTimeZone() {
var _myDate = new Date();
var _offset = _myDate.getTimezoneOffset();
document.cookie = "TIMEZONE_COOKIE=" + _offset;
})();
- Создаём javax фильтр, в котором будем получать значение данной куки и сохранять его в Session Scope бине.
public class TimezoneFilter implements Filter {
@Autowired
private ApplicationContext appContext;
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
Cookie[] cookies = httpServletRequest.getCookies();
if (cookies != null && cookies.length > 0) {
Optional<Cookie> cookieOpt = Arrays.stream(cookies)
.filter(c -> c.getName().equals("TIMEZONE_COOKIE"))
.findFirst();
if (cookieOpt.isPresent()) {
ClientInfoBean clientInfoBean = appContext.getBean(ClientInfoBean.class);
String timezone = "GMT";
int offset = -1 * Integer.parseInt(cookieOpt.get().getValue()) / 60;
if (offset >= 0) {
timezone = timezone + "+" + String.valueOf(offset);
} else {
timezone = timezone + String.valueOf(offset);
}
clientInfoBean.setTimezone(timezone);
}
}
chain.doFilter(request, response);
}
@Override
public void destroy() {}
}
- Устанавлием значение таймзоны в компоненте <f:convertDateTime/>
<h:outputText value="#{someBean.someDate}">
<f:convertDateTime pattern="dd.MM.yyyy HH:mm:ss" timeZone="#{clientInfoBean.timezone}"/>
</h:outputText>
Таким образом, данные, чувствительные к таймзоне, будут корректо отображаться у клиентов из любого региона