web-dev-qa-db-ja.com

JSFの場合-クライアントのロケールを取得する(ブラウザのタイムゾーンで時間を表示するには)

ユーザーへの情報の一部としてタイムスタンプを表示するWebアプリをJSF2.0で作成しています。自分の場所(ブラウザーのロケール)にローカライズされたタイムスタンプをユーザーに表示してもらいたい。

これまでのところ、私が何をしたとしても、タイムスタンプは常にサーバーのタイムゾーンにローカライズされているように見えます。

私はこれらの方法でロケールを取得しようとしました:

Locale browserLocale = FacesContext.getCurrentInstance().getViewRoot().getLocale();

または

Locale browserLocale = FacesContext.getCurrentInstance().getExternalContext().getRequestLocale();

どちらもサーバーのロケールを返しました。

次に、ロケールオブジェクトをSimpleDateFormatとともに使用して、タイムスタンプを出力します。

正しいAPIを使用していますか?
ブラウザのタイムゾーンを取得するには、クライアント側のコード(Javascript)を使用する必要があることをどこかで読みました。あれは正しいですか?どうしますか?

'n'Advanceに感謝します。

[〜#〜] update [〜#〜]が見つかりました this (jsTimezoneDetect)JavaScriptコード。しかし、タイムゾーンをJava Localeオブジェクトに変換する方法がまだわかりません

12
Ben

SimpleDateFormatの代わりに組み込みのフォーマットタグを使用する必要があります。あなたの質問は、国際ユーザーに日付と時刻を表示したいことを意味します。この場合、実際にはユーザーのローカル形式を使用する必要があります(それらは異なる傾向があります)。

タイムゾーンの場合、国際化とローカリゼーションとは関係ありません。つまり、米国にはいくつかの異なるタイムゾーンがあります。ここで使用できるアプローチは2つあります。

  1. タイムゾーン情報をユーザープロファイルに保存します(ある場合)。これが最も簡単な方法であり、組み込みの_<f:convertDateTime>_タグを使用できます。

  2. Webブラウザからタイムゾーン情報を取得します。ベンの例のように、Ajaxリクエストを介して取得できます。技術的には、ここで_<f:convertDateTime>_タグを使用することもできます。

  3. タイムスタンプをUTCで、ロケールに依存しない一般的な(または必要に応じて不変の)形式で送信し、クライアント側で解析して、JavaScriptの日付オブジェクトとロケールの形式を Globalize で作成できます。

いくつかの例を次に示しますが、最初に何かを説明しましょう。

_Locale browserLocale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
_

このwillは、Webブラウザのロケールを提供します(ただし、これはであるため、タイムゾーンは提供されません) notロケール関連)。実際にHTTPAccept-Languageヘッダーの内容を読み取り、可能な限り最適なロケールを選択します。それが機能しない場合は、_faces-config.xml_でサポートされているロケールが正しく設定されていることを確認してください。可能な限り最良のロケールでは、ユーザーが最も好むロケール(アプリケーションでサポートされている場合)を使用し、次に2番目に良いロケールを使用しようとすることを理解しています。いずれのロケールもサポートされていない場合は、アプリケーションのデフォルトのロケールにフォールバックします(ここでも、_faces-config.xml_にこの設定が必要です)。この設定がない場合は、サーバーのデフォルトのロケールにフォールバックします(または少なくともそう思います。それはちょっと理にかなっています)。

_Locale browserLocale = FacesContext.getCurrentInstance().getExternalContext().getRequestLocale();
_

これにより、Accept-Languageヘッダーの最上位ロケールが表示されます。 Webブラウザの設定を確認してください-Webブラウザとまったく同じでない限り、サーバーのロケールを提供する方法はほとんどありません。 WebブラウザのロケールがJVMでサポートされていない場合にのみ、サーバーのデフォルトを提供できます(これは少しありそうもないようです)。

ところで。 FacesContext.getCurrentInstance().getExternalContext().getRequestLocales()はイテレーターを提供するので、Accept-Languageヘッダーのロケールのリストを手動で繰り返すことができます。それはあなたに知らせるためだけです、あなたはおそらくそれを使うべきではありません(UIViewRootは本当に十分です)。

ここで、ユーザープロファイルとタイムゾーンを提供するメソッドを備えたBeanがあるとします。この方法は、2つの異なるタイムゾーンが同じUTCオフセットを持っているが、異なる日付で夏時間を切り替える可能性があるという意味で、Ajax呼び出しよりも優れています(つまり、一部のタイムスタンプが正しく印刷されません)。とにかく、このような場合は、タイムスタンプを次のようにフォーマットできます(日付も一部のBeanから取得されます)。

_<h:outputText value="#{someBean.timestamp}">
  <f:convertDateTime type="both" dateStyle="default" timeStyle="default" timeZone="#{userProfile.timeZone}" />
</h:outputtext>
_

次に、属性について説明します。

  • タイプ-何を表示するか、両方とも日付と時刻を意味します
  • dateStyle-日付のスタイル(short、medium、long、full、defaultから)。これは各ロケールに最も適切な形式を使用するため、ここでは実際にデフォルトを使用する必要があります
  • 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")の日付と時刻の形式しかありません。そこで、短いものを使うことにしました。
Globalizeの文化はアンダースコアではなくハイフンで区切られているため、たとえば「fr_CA」ではなく「fr-CA」が必要になることにも注意してください。
その方法を使用したい場合で、より具体的な例が必要な場合はお知らせください。

27
Paweł Dyda

成功しました。これが私がしたことです:

JavaScript値をサーバーに送信できるように、JSFに非表示の入力フィールドを追加しました。

<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);

次に、日付をフォーマットする必要があるときはいつでも、上記で作成した日付フォーマッターを使用します。

7
Ben

jsTimezoneDetect を試して、クライアント側でタイムゾーンを検出し、サーバーに送信することをお勧めします。

UPDATE:ユーザーのロケールを取得するには、次のことを試してください。

HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
Locale locale = request.getLocale();

Accept-Languageヘッダーに基づいてクライアントに受け入れられるロケールを、優先ロケールから降順で示すロケールオブジェクトの列挙を返します。クライアント要求がAccept-Languageヘッダーを提供しない場合、このメソッドは、サーバーのデフォルトロケールである1つのロケールを含む列挙型を返します。

2
Mr.J4mes

別のオプションは、ホームページの準備ができたときに実行される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;
    }

フェイスレットは、Cookieが存在する場合、その値を使用します。

<h:outputText value="#{bean.time}">
   <f:convertDateTime
       dateStyle="full"
       timeStyle="full"
       type="both"
       timeZone="#{cookie.timezoneCookie.value}">
   </f:convertDateTime>
</h:outputText>
2
Ghasfarost

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}" />
0
Adrian

必要なのがLocaleオブジェクトを必要としないユーザーの現地時間でタイムスタンプを表示することだけである場合(ユーザーの時間オフセットをGMT + 0時間に追加する必要があります)、Y timezone.offset()の値を送信する必要があります(リンクの例から)サーバーへ(パラメータ付きのサーブレット投稿を使用して実行できます)

次に、このオフセットをサーバー上に作成された日付オブジェクトに追加します(サーバー上のロケールをGMT + 00に設定します)

そうすれば、Webアプリにログインしているユーザーの正しい時刻でタイムスタンプを作成できます

(それは私が自分でしたことです...)

0
Daniel