我正在JSF 2.0中编写一个webapp,它将Timestamps作为信息的一部分显示给用户。 我希望用户看到本地化到其位置的时间戳(浏览器的语言环境)。
到目前为止,无论我做了什么,时间戳总是会显示为服务器时区的本地化。
我尝试使用以下方法获取语言环境:
Locale browserLocale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
或
Locale browserLocale = FacesContext.getCurrentInstance().getExternalContext().getRequestLocale();
两者都返回了服务器的语言环境。
然后我使用带有SimpleDateFormat
的语言环境对象来打印时间戳。
我使用的是正确的API吗? 我在某处读过你必须使用客户端代码(Javascript)来获取浏览器的时区。那是对的吗?你会怎么做?
感谢'n'Advance。
UPDATE 找到this(jsTimezoneDetect)JavaScript代码。但我仍然不确定如何将时区转换为Java Locale
对象
答案 0 :(得分:27)
您可能应该使用内置格式标记而不是SimpleDateFormat。你的问题暗示你想向国际用户显示日期和时间,在这种情况下你应该真正使用用户的本地格式(它们往往会有所不同,你知道)。
在时区的情况下,它与国际化和本地化无关,即在美国有几个不同的时区。您可以在此处使用两种方法:
在用户个人资料中存储时区信息(如果有的话)。这是最简单的方法,允许您使用内置的<f:convertDateTime>
代码。
从网络浏览器获取时区信息。您可以通过Ajax请求获取它,就像在Ben的示例中一样。从技术上讲,您也可以在此处使用<f:convertDateTime>
标记。
您可以用一些常见的,与语言环境无关的(或者如果您愿意的话不变)格式发送UTC的时间戳,在客户端解析它以创建JavaScript的日期对象和Globalize的语言环境格式
接下来会有一些例子,但我先解释一下。
Locale browserLocale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
此将为您提供网络浏览器的区域设置(但不是时区,因为 不 区域设置相关)。它实际上将读取HTTP Accept-Language标头的内容并选择最佳的区域设置。如果它不适合您,请确保您在faces-config.xml
中正确设置了支持的区域设置。通过最好的Locale,我知道它会尝试使用用户最喜欢的Locale(如果你的应用程序支持),那么第二好等等。如果没有支持任何语言环境,它将回退到应用程序的默认语言环境(同样,faces-config.xml
必须具有此设置)或服务器的默认语言环境(如果缺少此设置)(或者至少我认为如此,它有点意义)。
Locale browserLocale = FacesContext.getCurrentInstance().getExternalContext().getRequestLocale();
这个将从Accept-Language标题中为您提供顶级区域设置。请检查您的网络浏览器的设置 - 它几乎无法为您提供服务器区域设置,除非它们与您的网络浏览器完全相同。当且仅当JVM不支持Web浏览器的Locale时(这似乎不太可能),它可以为您提供服务器的默认值。
顺便说一句。 FacesContext.getCurrentInstance().getExternalContext().getRequestLocales()
将为您提供迭代器,以便您可以手动迭代Accept-Language标头中的Locales列表。它只是让你知道,你可能不应该使用它(UIViewRoot真的够了)。
现在,假设您有一些带有用户配置文件的bean以及为您提供时区的方法。此方法优于Ajax调用,因为可能会发生两个不同时区具有相同的UTC偏移但在不同日期切换夏令时(换句话说,某些时间戳将被错误打印)。无论如何,在这种情况下,您可以像这样设置时间戳(日期也来自某个bean):
<h:outputText value="#{someBean.timestamp}">
<f:convertDateTime type="both" dateStyle="default" timeStyle="default" timeZone="#{userProfile.timeZone}" />
</h:outputtext>
现在让我解释一下这些属性:
默认情况下,标记将使用当前视图区域设置,因此您不必担心此部分,尤其是在正确设置区域设置支持的情况下。
将它与Ajax结合起来(参见Ben的回答)很容易(我认为)。
我还提到你可以写出不变的日期,在客户端解析它们,然后用Globalize格式化它们。假设你已经解析了日期(这取决于你想要使用的表示,所以我将跳过这一部分),可以这样做:
// you also have to assign the culture based on UIViewRoot locale and send it out with JavaScript
Globalize.culture(theLocale);
var formattedDateTime = Globalize.format(parsedDateTime, "f"); // this will use short date time format
与Java不同,Globalize只有短(“f”)和长(“F”)日期和时间格式。所以我决定使用短篇
还请记住,全球化文化是通过连字符而不是下划线分开的,所以你需要“fr-CA”,而不是“fr_CA”。
如果您想使用该方法并需要更具体的示例,请告诉我。
答案 1 :(得分:7)
成功。 这是我做的:
向JSF添加了一个隐藏的输入字段,以便我可以将JavaScript值发送到服务器:
<h:form prependId="false">
<h:inputText id="timezone_holder" value="#{bean.timezone}" styleClass="hide">
<f:ajax listener="#{bean.timezoneChangedListener}"></f:ajax>
</h:inputText>
</h:form>
使用上面的插件,我运行了JavaScript
代码来检索浏览器的偏移量。
$(document).ready(function() {
var timezone = jstz.determine_timezone();
$("#timezone_holder").val(timezone.offset());
$("#timezone_holder").change();
});
当更改时区输入时(从上面的javascript代码启动)我在eventListener中运行此代码:
String strFromJavaScript = getTimezone();
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext()
.getRequest();
Locale browserLocale = request.getLocale();
TimeZone tz = TimeZone.getTimeZone("GMT" + strFromJavaScript);
// set time zone
SimpleDateFormat formatter = new SimpleDateFormat("MMM d, yyyy, HH:mm", browserLocale);
formatter.setTimeZone(tz);
然后,每当我需要格式化日期时,我都会使用上面创建的日期格式化程序。
答案 2 :(得分:2)
您可能需要尝试jsTimezoneDetect来检测客户端的时区并发送到服务器。
更新:要获取用户的区域设置,您可以尝试以下操作:
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
Locale locale = request.getLocale();
返回Locale对象的枚举,指示递减 从首选语言环境开始的顺序,即语言环境 基于Accept-Language标头的客户端可以接受。如果 客户端请求不提供Accept-Language标头,此方法 返回包含一个Locale的Enumeration,它是默认的语言环境 服务器。
答案 3 :(得分:2)
另一种选择是在主页准备就绪时执行的Javascript上创建一个cookie。之后,cookie将存在于每个后续请求中并且可用
您的Javascript可以使用jQuery和jsTimezoneDetect
$(document).ready(function() {
setTimezoneCookie();
});
function setTimezoneCookie() {
var timezone = jstz.determine().name();
if (null == getCookie("timezoneCookie")) {
document.cookie = "timezoneCookie=" + timezone;
}
}
function getCookie(cookieName) {
var cookieValue = document.cookie;
var cookieStart = cookieValue.indexOf(" " + cookieName + "=");
if (cookieStart == -1) {
cookieStart = cookieValue.indexOf(cookieName + "=");
}
if (cookieStart == -1) {
cookieValue = null;
} else {
cookieStart = cookieValue.indexOf("=", cookieStart) + 1;
var cookieEnd = cookieValue.indexOf(";", cookieStart);
if (cookieEnd == -1) {
cookieEnd = cookieValue.length;
}
cookieValue = unescape(cookieValue.substring(cookieStart, cookieEnd));
}
return cookieValue;
}
如果存在,您的Facelet将使用cookie的值:
<h:outputText value="#{bean.time}">
<f:convertDateTime
dateStyle="full"
timeStyle="full"
type="both"
timeZone="#{cookie.timezoneCookie.value}">
</f:convertDateTime>
</h:outputText>
答案 4 :(得分:0)
如果您只需要显示用户当地时间的时间戳,则不需要Locale对象(您需要将用户小时偏移量添加到GMT + 0时间),Y 您需要将timezone.offset()的值(从链接中的示例)发送到服务器(您可以通过使用带参数的servlet post来实现)
然后将此偏移量添加到服务器上创建的日期对象(将服务器上的区域设置设置为GMT + 00)
通过这种方式,您将使用登录到您的Web应用程序的用户的正确时间创建时间戳
(这就是我自己做的......)
答案 5 :(得分:0)
您也可以直接在JSF代码中使用它:
<script type="text/javascript">
$(document).ready(function () {
var timezone = jstz.determine_timezone();
$("#timezone_holder").val(timezone.name()); //use TimeZone name instead of offset
$("#timezone_holder").change();
});
</script>
然后你可以在JSF转换器中重用timezonename:
<f:convertDateTime pattern="dd.MM.yyyy HH:mm" timeZone="#{bean.timezone}" />