在JSF中 - 获取客户端的区域设置(在浏览器的时区中显示时间)

时间:2011-12-22 07:10:55

标签: javascript jsf localization jsf-2

我正在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对象

6 个答案:

答案 0 :(得分:27)

您可能应该使用内置格式标记而不是SimpleDateFormat。你的问题暗示你想向国际用户显示日期和时间,在这种情况下你应该真正使用用户的本地格式(它们往往会有所不同,你知道)。

在时区的情况下,它与国际化和本地化无关,即在美国有几个不同的时区。您可以在此处使用两种方法:

  1. 在用户个人资料中存储时区信息(如果有的话)。这是最简单的方法,允许您使用内置的<f:convertDateTime>代码。

  2. 从网络浏览器获取时区信息。您可以通过Ajax请求获取它,就像在Ben的示例中一样。从技术上讲,您也可以在此处使用<f:convertDateTime>标记。

  3. 您可以用一些常见的,与语言环境无关的(或者如果您愿意的话不变)格式发送UTC的时间戳,在客户端解析它以创建JavaScript的日期对象和Globalize的语言环境格式

  4. 接下来会有一些例子,但我先解释一下。

    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>
    

    现在让我解释一下这些属性:

    • type - 要显示的内容,两者均表示日期和时间
    • dateStyle - 日期样式(短,中,长,完整,默认)。你应该在这里使用默认值,因为这将为每个Locale使用最合适的格式
    • timeStyle - 类似于日期样式但适用于时间部分
    • timeZone - 采用UTC偏移量(因此您无需转换任何内容)或时区名称(即America / Los_Angeles)。

    默认情况下,标记将使用当前视图区域设置,因此您不必担心此部分,尤其是在正确设置区域设置支持的情况下。

    将它与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}" />