29

私たちのアプリケーションは、地理的に異なる場所からのユーザーを処理するように設計されています。

現在のエンド ユーザーの現地時間とタイム ゾーンが何であるかを検出できません。彼らは、ヨーロッパ/ロンドンのタイムゾーンからアクセスしても、sv-se、en-us、ta-In などの異なる文化を選択します..

米国のホスティングサーバーでホストしました。アプリケーションユーザーはNorway/Denmark/Sweden/UK/USA/India

問題はDateTime.Now、レコードの作成日/更新日などを保存するために使用されていることです。

サーバーは米国で実行されるため、すべてのユーザーデータは米国時間として保存されます:(

SOで調査した後、すべての履歴日付をDBに保存することにしましたDateTime.UtcNow

問題:

ここに画像の説明を入力

に作成されたレコードがあり29 Dec 2013, 3:15 P.M Swedish timeます。

 public ActionResult Save(BookingViewModel model)
    {
        Booking booking = new Booking();
        booking.BookingDateTime = model.BookingDateTime; //10 Jan 2014 2:00 P.M
        booking.Name = model.Name;
        booking.CurrentUserId = (User)Session["currentUser"].UserId;
        //USA Server runs in Pacific Time Zone, UTC-08:00
        booking.CreatedDateTime = DateTime.UtcNow; //29 Dec 2013, 6:15 A.M
        BookingRepository.Save(booking);
        return View("Index");
    }

インド/スウェーデン/アメリカでログインしたユーザーに同じ履歴時間を表示したい。

現在、ログインしている現在のカルチャ ユーザーを使用して、構成ファイルからタイムゾーンを選択し、TimeZoneInfo クラスでの変換に使用しています。

<appSettings>
    <add key="sv-se" value="W. Europe Standard Time" />
    <add key="ta-IN" value="India Standard Time" />
</appSettings>

    private DateTime ConvertUTCBasedOnCulture(DateTime utcTime)
    {
        //utcTime is 29 Dec 2013, 6:15 A.M
        string TimezoneId =                  
                System.Configuration.ConfigurationManager.AppSettings
                [System.Threading.Thread.CurrentThread.CurrentCulture.Name];
        // if the user changes culture from sv-se to ta-IN, different date is shown
        TimeZoneInfo tZone = TimeZoneInfo.FindSystemTimeZoneById(TimezoneId);

        return TimeZoneInfo.ConvertTimeFromUtc(utcTime, tZone);
    }
    public ActionResult ViewHistory()
    {
        List<Booking> bookings = new List<Booking>();
        bookings=BookingRepository.GetBookingHistory();
        List<BookingViewModel> viewModel = new List<BookingViewModel>();
        foreach (Booking b in bookings)
        {
            BookingViewModel model = new BookingViewModel();
            model.CreatedTime = ConvertUTCBasedOnCulture(b.CreatedDateTime);
            viewModel.Add(model);
        }
        return View(viewModel);
    }

コードを表示

   @Model.CreatedTime.ToString("dd-MMM-yyyy - HH':'mm")

注: ユーザーは、ログインする前にカルチャ/言語を変更できます。米国のサーバーで実行されるローカリゼーション ベースのアプリケーションです。

を見NODATIMEたことがありますが、別の場所でホストされている多文化 Web アプリケーションにどのように役立つか理解できませんでした。

質問

29 Dec 2013, 3:15 P.MINDIA/USA/Anywhere` にログインしているユーザーに同じレコード作成日を表示するにはどうすればよいですか?

現在、私のロジックはConvertUTCBasedOnCulture、文化にログインしているユーザーに基づいています。ユーザーはインド/米国のどの文化を使用してもログインできるため、これは文化に関係なく行う必要があります。

データベース列

作成時間:SMALLDATETIME

更新:試みられた解決策:

DATABASE COLUMN TYPE: DATETIMEOFFSET

UI

最後に、各リクエストで以下の Momento.js コードを使用して現在のユーザーの現地時間を送信しています

$.ajaxSetup({
    beforeSend: function (jqXHR, settings) {
        try {
      //moment.format gives current user date like 2014-01-04T18:27:59+01:00
            jqXHR.setRequestHeader('BrowserLocalTime', moment().format());
        }
        catch (e) {
        }
    }
});

応用

public static DateTimeOffset GetCurrentUserLocalTime()
{
    try
    {
      return 
      DateTimeOffset.Parse(HttpContext.Current.Request.Headers["BrowserLocalTime"]);
    }
    catch
    {
        return DateTimeOffset.Now;
    }
}

それから呼ばれた

 model.AddedDateTime = WebAppHelper.GetCurrentUserLocalTime();

ビューで

@Model.AddedDateTime.Value.LocalDateTime.ToString("dd-MMM-yyyy - HH':'mm")

dd-MMM-yyyy CET/PSTビューでは、ローカル時間をユーザーに表示しますが、 (2 時間前)のように表示したいです。

この 2 時間前は、エンド ユーザーの現地時間から計算する必要があります。タイムゾーン表示とローカルユーザー計算で作成/編集されたスタックオーバーフローの質問とまったく同じです。

例: answered Jan 25 '13 at 17:49 CST (6 hours/days/month ago)したがって、USA/INDIA ユーザーからの別の視聴者は、この記録が INDIA/USA 現在時刻から正確に 6 時間で作成されたことを本当に理解できます。

表示形式と計算以外はほぼできたと思います。これどうやってするの?

4

5 に答える 5

14

DateTimeOffsetの代わりに aを保存する必要があるようですDateTime。値を作成しているユーザーにローカルを保存することもできDateTimeますが、それは注文操作などを実行できないことを意味します。DateTime.UtcNowユーザーのローカルの日付/時刻を示すために何も保存しないため、単に使用することはできませんレコードが作成されたとき。

または、ユーザーのタイムゾーンとともに瞬間を保存することもできます。これは実現が困難ですが、「1 時間後のユーザーの現地時間は?」などと言うことができるため、より多くの情報が得られます。

サーバーのホスティングは無関係であるべきです - サーバーのタイムゾーンを決して使用すべきではありません。ただし、ユーザーの適切な UTC オフセット (またはタイム ゾーン) を知る必要があります。これは、カルチャだけに基づいて行うことはできません。ユーザーのマシンで Javascript を使用して、関心のある時間 (必ずしも「今」ではない) の UTC オフセットを決定する必要があります。

値を格納する方法を理解したら、値を取得するのは簡単です。すでに UTC インスタントとオフセットを格納している場合は、そのオフセットを適用するだけで、元のユーザーのローカル時間に戻ります。値をテキストに変換する方法については述べていませんが、単純にドロップアウトする必要があります-値をフォーマットするだけで、元の現地時間を取得する必要があります.

Noda Time を使用することにした場合は、OffsetDateTime代わりにDateTimeOffset.

于 2013-12-30T16:55:40.310 に答える
11

標準的なアプローチは、特定の瞬間が重要な場合、常に時刻データを UTC として保存することです。その時間は、タイム ゾーンの変更や文化の影響を受けません。

タイム ゾーンで時刻を表示する最も一般的な方法は、時刻を UTC として保存し、値を表示するときに現在のユーザーのカルチャとタイム ゾーンの組み合わせに変換することです。このアプローチでは、ストレージにファイルされた日付時刻が 1 つだけ必要です。

Web ケース (ASP.Net など) の場合、最初にユーザーのカルチャ/タイム ゾーンを把握し、それをサーバーに送信する必要がある場合があることに注意してください (この情報は GET 要求では使用できないため)、ブラウザーで時刻の書式設定を行う必要があります。

「同じ履歴時間を表示する」ものによっては、現在のカルチャや現在のオフセットなどの追加情報を保存する必要がある場合があります。元のユーザーが見たのとまったく同じ時間を表示する必要がある場合は、文字列表現を保存することもできます (形式/翻訳は後で変更される可能性があり、値が異なって見えるため、これも珍しいことです)。

注: カルチャとタイム ゾーンは関連付けられていないため、米国の PST タイム ゾーンで IN-IN カルチャなどのケースを処理する方法を決定する必要があります。

于 2013-12-25T19:54:43.393 に答える
9

質問の言い回しに少し混乱していますが、ユーザーのタイムゾーンを特定したいようです。

  • 彼らに聞いてみましたか?多くのアプリケーションでは、ユーザーがユーザー設定でタイムゾーンを選択する必要があります。

  • ドロップダウン リスト、リストのペア (国、次に国内のタイム ゾーン)、または地図ベースのタイム ゾーン ピッカー コントロールから選択できます。

  • ユーザーが変更しない限り、推測してそれをデフォルトとして使用できます。

そのルートをたどる場合は、IANA/Olson タイム ゾーンを使用できるようにする必要があります。これは、野田時間が機能する場所です。からアクセスできますDateTimeZoneProviders.Tzdb

UTC を使用している場合、ホスティングの場所は関係ありません。それはいい。

また、野田時間を使用している場合は、おそらくSystemClock.Instance.Nowの代わりに使用する必要がありDateTime.UtcNowます。

ここここも参照してください。

また、別の解決策は、UTC 時刻をブラウザーに渡して JavaScriptDateオブジェクトにロードすることです。ブラウザーはそれをユーザーの現地時間に変換できます。これを簡単にするために、moment.jsのようなライブラリを使用することもできます。


アップデート

文化コードをタイムゾーンにマッピングするアプローチについて:

<appSettings>
    <add key="sv-se" value="W. Europe Standard Time" />
    <add key="ta-IN" value="India Standard Time" />
</appSettings>

いくつかの理由により、それは機能しません。

  • 多くの人は、物理的にいる地域とは異なる文化設定をコンピューターで使用してen-USde-DEます。

  • 国を含むカルチャ コードは、言語の方言を区別するために使用されます。が表示されている場合es-MX、それは「メキシコで話されているスペイン語」を意味します。ユーザーが実際にメキシコにいるという意味ではありません。es-ESこれは、「スペインで話されているスペイン語」を意味するのと比較して、ユーザーがスペイン語の方言を話していることを意味します。

  • カルチャ コードの国部分が信頼できる場合でも、複数のタイム ゾーンを持つ国が多数あります。たとえば、 のマッピング リストには何を入れますen-USか? 私たち全員が東部標準時にいると思い込んではいけません。

ここで、あなたの現在のアプローチがうまくいかない理由を説明しました。私の最初のアドバイスに従うことを強くお勧めします。非常に簡単に:

  1. ユーザーのタイムゾーンを決定します。できれば質問して、上記でリンクしたユーティリティのいずれかの支援を受けてください。

  2. UTC を保存しているので、そのタイム ゾーンに変換して表示するだけです。

    Microsoft タイム ゾーンの使用
    TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
    DateTime localDatetime = TimeZoneInfo.ConvertTimeFromUtc(yourUTCDateTime, tz);
    
    IANA タイム ゾーンと野田時間の使用
    DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/Stockholm"];
    Instant theInstant = Instant.FromDateTimeUtc(yourUTCDateTime);
    LocalDateTime localDateTime = theInstant.InZone(tz);
    
于 2013-12-28T17:27:07.227 に答える
1

私が最近取り組んだアプリケーションでも同様の問題に直面しました。開発中、すべてが同じタイム ゾーンにあり、問題は認識されませんでした。いずれにせよ、すでに DB にあるすべての日時情報を変換することは言うまでもなく、変更するのが面倒だった多くのレガシー コードがありました。そのため、DateTimeOffset への変更はオプションではありませんでした。しかし、途中でサーバー時間からユーザー時間に変換し、途中でユーザー時間からサーバー時間に変換することで、すべての一貫性を確保することができました。また、境界である日付と時間の比較でこれを行うことも重要でした。したがって、ユーザーが真夜中に何かが期限切れになると予想した場合、その時間をサーバー時間に変換し、すべての比較をサーバー時間で行います。

Hear は、タイム ゾーンの問題に対するいくつかの優れた解決策があるように見えるスレッドです。

ユーザーのタイムゾーンを決定する

于 2014-01-04T10:02:08.940 に答える
0

ユーザーが履歴を表示しているロケールに関係なく、一貫した日付/時刻履歴をユーザーに表示する場合は、次のようにします。

  1. の間Save、UTC「作成」日時だけでなく、検出されたロケールも保存します
  2. storedsaved from localeを使用して元の日付/時刻を計算し、表示する文字列を発行します (つまり、表示するときに現在のユーザー ロケールを使用しないでください)。

ストレージを修正する機能がない場合は、送信を変更して「現在のクライアント時間」を送信し、文字どおりに保存して (UTC に変換しないでください)、文字どおりに表示することができます (検出されたカルチャに変換しないでください)。 )

しかし、あなたの質問の下の私のコメントで言っているように、私はあなたの要件が正しいかどうか確信が持てません.

于 2013-12-30T16:39:27.550 に答える