簡體   English   中英

如何在c#中獲取當前用戶時區

[英]How to get current user timezone in c#

我正在 MVC3 中構建一個應用程序,當用戶進入我的網站時,我想知道該用戶的時區。 我想知道如何在 c# 中而不是在 javaScript 中執行此操作?

如前所述,您需要您的客戶端告訴您的 ASP.Net 服務器有關它們所在時區的詳細信息。

這是一個例子。

我有一個 Angular 控制器,它從我的 SQL Server 數據庫以 JSON 格式加載記錄列表。 問題是,這些記錄中的DateTime值在 UTC 時區中,我想向用戶顯示其本地時區中的日期/時間。

我使用 JavaScript 的“ getTimezoneOffset() ”函數確定用戶的時區(以分鍾為getTimezoneOffset() ,然后將此值附加到我嘗試調用的 JSON 服務的 URL:

$scope.loadSomeDatabaseRecords = function () {

    var d = new Date()
    var timezoneOffset = d.getTimezoneOffset();

    return $http({
        url: '/JSON/LoadSomeJSONRecords.aspx?timezoneOffset=' + timezoneOffset,
        method: 'GET',
        async: true,
        cache: false,
        headers: { 'Accept': 'application/json', 'Pragma': 'no-cache' }
    }).success(function (data) {
        $scope.listScheduleLog = data.Results;
    });
}

在我的 ASP.Net 代碼中,我提取了timezoneOffset參數...

int timezoneOffset = 0;

string timezoneStr = Request["timezoneOffset"];
if (!string.IsNullOrEmpty(timezoneStr))
    int.TryParse(timezoneStr, out timezoneOffset);

LoadDatabaseRecords(timezoneOffset);

...並將其傳遞給我的函數,該函數從數據庫中加載記錄。

這有點混亂,因為我想在數據庫中的每條記錄上調用我的 C# FromUTCData函數,但LINQ to SQL無法將原始 SQL 與 C# 函數結合起來。

解決方案是先讀入記錄,然后遍歷它們,將時區偏移量應用到每條記錄中的DateTime字段。

public var LoadDatabaseRecords(int timezoneOffset)
{
    MyDatabaseDataContext dc = new MyDatabaseDataContext();

    List<MyDatabaseRecords> ListOfRecords = dc.MyDatabaseRecords.ToList();

    var results = (from OneRecord in ListOfRecords
           select new
           {
               ID = OneRecord.Log_ID,
               Message = OneRecord.Log_Message,
               StartTime =  FromUTCData(OneRecord.Log_Start_Time, timezoneOffset),
               EndTime = FromUTCData(OneRecord.Log_End_Time, timezoneOffset)
           }).ToList();

    return results;
}

public static DateTime? FromUTCData(DateTime? dt, int timezoneOffset)
{
    //  Convert a DateTime (which might be null) from UTC timezone
    //  into the user's timezone. 
    if (dt == null)
        return null;

    DateTime newDate = dt.Value - new TimeSpan(timezoneOffset / 60, timezoneOffset % 60, 0);
    return newDate;
}

不過,它運行良好,並且在編寫 Web 服務以向世界不同地區的用戶顯示日期/時間時,此代碼非常有用。

現在,我在蘇黎世時間上午 11 點寫這篇文章,但如果你在洛杉磯閱讀它,你會看到我在凌晨 2 點(你的當地時間)編輯它。 使用這樣的代碼,您可以讓您的網頁顯示對您網站的國際用戶有意義的日期時間。

呼。

希望這可以幫助。

這是不可能的服務器端,除非您通過用戶 ip 地址假設它或讓用戶以某種形式的配置文件設置它。 您可以通過 javascript 獲取客戶時間。

有關 javacript 解決方案,請參見此處: Getting the client's timezone in JavaScript

我遇到了同樣的問題,不幸的是,服務器無法知道客戶端時區。 如果您願意,可以在進行 ajax 調用時將客戶端時區作為標頭發送。

如果您想了解有關添加標頭的更多信息,這篇文章可能有助於如何向請求添加標頭: 如何使用 js 或 jQuery 向 ajax 請求添加自定義 HTTP 標頭?

new Date().getTimezoneOffset();//gets the timezone offset

如果您不想每次都添加標頭,則可以考慮設置 cookie,因為 cookie 是隨所有 httpRequest 一起發送的,您可以處理 cookie 以獲取服務器端的客戶端時區。 但我不喜歡添加 cookie,原因與它們隨所有 http 請求一起發送的原因相同。 謝謝。

您將需要同時使用客戶端和服務器端技術。

在客戶端:
(選一個)

  • 這適用於大多數現代瀏覽器:

     Intl.DateTimeFormat().resolvedOptions().timeZone
  • 還有jsTimeZoneDetectjstz.determine()矩時區moment.tz.guess()對舊版瀏覽器的功能,認為這些庫一般只在舊的應用程序使用。

兩者的結果將是IANA 時區標識符,例如America/New_York 以您喜歡的任何方式將該結果發送到服務器。

在服務器端:
(選一個)

  • 使用TimeZoneInfo (僅限非 Windows 系統):

     TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
  • 使用TimeZoneConverter (在任何操作系統上):

     TimeZoneInfo tzi = TZConvert.GetTimeZoneInfo("America/New_York");
  • 使用NodaTime (在任何操作系統上):

     DateTimeZone tz = DateTimeZoneProviders.Tzdb["America/New_York"];

對於 Dot Net 3.5 及更高版本,您可以使用:

TimeZoneInfo.Local.GetUtcOffset(DateTime.UtcNow);

但是對於低於 3.5 版的 Dot Net,您可以通過這種方式手動處理它:

首先,從客戶端獲取Offset並將其存儲在cookie中

function setTimezoneCookie(){
 
var timezone_cookie = "timezoneoffset";

// if the timezone cookie does not exist create one.
if (!$.cookie(timezone_cookie)) { 

    // check if the browser supports cookie
    var test_cookie = 'test cookie';
    $.cookie(test_cookie, true);

    // browser supports cookie
    if ($.cookie(test_cookie)) { 
     
        // delete the test cookie
        $.cookie(test_cookie, null);
     
        // create a new cookie 
        $.cookie(timezone_cookie, new Date().getTimezoneOffset());

        // re-load the page
        location.reload(); 
    }
}
// if the current timezone and the one stored in cookie are different
// then store the new timezone in the cookie and refresh the page.
else {         

    var storedOffset = parseInt($.cookie(timezone_cookie));
    var currentOffset = new Date().getTimezoneOffset();

    // user may have changed the timezone
    if (storedOffset !== currentOffset) { 
        $.cookie(timezone_cookie, new Date().getTimezoneOffset());
        location.reload();
    }
}

}

之后,您可以像這樣在后端代碼中使用 cookie:

   public static string ToClientTime(this DateTime dt)
{
    // read the value from session
    var timeOffSet = HttpContext.Current.Session["timezoneoffset"];  
 
    if (timeOffSet != null) 
    {
        var offset = int.Parse(timeOffSet.ToString());
        dt = dt.AddMinutes(-1 * offset);
 
        return dt.ToString();
    }
 
    // if there is no offset in session return the datetime in server timezone
    return dt.ToLocalTime().ToString();
}

我知道用戶詢問了非 javascript 解決方案,但我想發布一個我想出的 javascript 解決方案。 我找到了一些 js 庫(jsTimezoneDetect、momentjs),但它們的輸出是 IANA 代碼,這似乎沒有幫助我在 C# 中獲取 TimeZoneInfo 對象。 我借鑒了 jsTimezoneDetect 的想法。 在 javascript 中,我獲取 BaseUtcOffset 和 DST 的第一天並發送到服務器。 然后服務器將其轉換為 TimeZoneInfo 對象。

現在我不在乎客戶時區是否被選擇為“太平洋時間(美國)”或“下加利福尼亞”,因為兩者都會創建正確的時間轉換(我認為)。 如果我找到多個匹配項,我目前只選擇第一個找到的 TimeZoneInfo 匹配項。

然后我可以將我的 UTC 日期從數據庫轉換為本地時間:

DateTime clientDate = TimeZoneInfo.ConvertTimeFromUtc(utcDate, timeZoneInfo);

Javascript

// Time zone.  Sets two form values:
// tzBaseUtcOffset: minutes from UTC (non-DST)
// tzDstDayOffset: number of days from 1/1/2016 until first day of DST ; 0 = no DST
var form = document.forms[0];
var janOffset = -new Date(2016, 0, 1).getTimezoneOffset();      // Jan
var julOffset = -new Date(2016, 6, 1).getTimezoneOffset();      // Jul
var baseUtcOffset = Math.min(janOffset, julOffset);             // non DST offset (winter offset)
form.elements["tzBaseUtcOffset"].value = baseUtcOffset;
// Find first day of DST (from 1/1/2016)
var dstDayOffset = 0;
if (janOffset != julOffset) {
    var startDay = janOffset > baseUtcOffset ? 180 : 0; // if southern hemisphere, start 180 days into year
    for (var day = startDay; day < 365; day++) if (-new Date(2016, 0, day + 1, 12).getTimezoneOffset() > baseUtcOffset) { dstDayOffset = day; break; }    // noon
}
form.elements["tzDstDayOffset"].value = dstDayOffset;

C#

    private TimeZoneInfo GetTimeZoneInfo(int baseUtcOffset, int dstDayOffset) {

        // Converts client/browser data to TimeZoneInfo
        // baseUtcOffset: minutes from UTC (non-DST)
        // dstDayOffset: number of days from 1/1/2016 until first day of DST ; 0 = no DST
        // Returns first zone info that matches input, or server zone if none found

        List<TimeZoneInfo> zoneInfoArray = new List<TimeZoneInfo>();    // hold multiple matches
        TimeSpan timeSpan = new TimeSpan(baseUtcOffset / 60, baseUtcOffset % 60, 0);
        bool supportsDst = dstDayOffset != 0;
        foreach (TimeZoneInfo zoneInfo in TimeZoneInfo.GetSystemTimeZones()) {
            if (zoneInfo.BaseUtcOffset.Equals(timeSpan) && zoneInfo.SupportsDaylightSavingTime == supportsDst) {
                if (!supportsDst) zoneInfoArray.Add(zoneInfo);
                else {
                    // Has DST. Find first day of DST and test for match with sent value. Day = day offset into year
                    int foundDay = 0;
                    DateTime janDate = new DateTime(2016, 1, 1, 12, 0, 0);  // noon
                    int startDay = zoneInfo.IsDaylightSavingTime(janDate) ? 180 : 0;    // if southern hemsphere, start 180 days into year
                    for (int day = startDay; day < 365; day++) if (zoneInfo.IsDaylightSavingTime(janDate.AddDays(day))) { foundDay = day; break; }
                    if (foundDay == dstDayOffset) zoneInfoArray.Add(zoneInfo);
                }
            }
        }
        if (zoneInfoArray.Count == 0) return TimeZoneInfo.Local;
        else return zoneInfoArray[0];
    }

看看這個asp.net c#解決方案

TimeZoneInfo mytzone = TimeZoneInfo.Local;

您可以從客戶端到服務器獲取此信息(任何 Web API 調用)

var timezoneOffset = new Date().getTimezoneOffset();

借助timezoneoffset詳細信息,您可以實現相同的目標。 在我的情況下,我將 UTC DateTime 轉換為服務器端的客戶端本地日期時間。

DateTime clientDateTime = DateTime.UtcNow - new TimeSpan(timezoneOffset / 60, timezoneOffset % 60, 0);

點擊代碼示例

System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_TIMEZONE"] ;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM