简体   繁体   English

如何在c#中获取当前用户时区

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

I am building an application in MVC3 and when a user comes into my site I want to know that user's timezone.我正在 MVC3 中构建一个应用程序,当用户进入我的网站时,我想知道该用户的时区。 I want to know how to do this in c# not in javaScript?我想知道如何在 c# 中而不是在 javaScript 中执行此操作?

As has been mentioned, you need your client to tell your ASP.Net server details about which timezone they're in.如前所述,您需要您的客户端告诉您的 ASP.Net 服务器有关它们所在时区的详细信息。

Here's an example.这是一个例子。

I have an Angular controller, which loads a list of records from my SQL Server database in JSON format.我有一个 Angular 控制器,它从我的 SQL Server 数据库以 JSON 格式加载记录列表。 The problem is, the DateTime values in these records are in the UTC timezone, and I want to show the user the date/times in their local timezone.问题是,这些记录中的DateTime值在 UTC 时区中,我想向用户显示其本地时区中的日期/时间。

I determine the user's timezone (in minutes) using the JavaScript " getTimezoneOffset() " function, then append this value to the URL of the JSON service I'm trying to call:我使用 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;
    });
}

In my ASP.Net code, I extract the timezoneOffset parameter...在我的 ASP.Net 代码中,我提取了timezoneOffset参数...

int timezoneOffset = 0;

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

LoadDatabaseRecords(timezoneOffset);

... and pass it to my function which loads the records from the database. ...并将其传递给我的函数,该函数从数据库中加载记录。

It's a bit messy as I want to call my C# FromUTCData function on each record from the database, but LINQ to SQL can't combine raw SQL with C# functions.这有点混乱,因为我想在数据库中的每条记录上调用我的 C# FromUTCData函数,但LINQ to SQL无法将原始 SQL 与 C# 函数结合起来。

The solution is to read in the records first, then iterate through them, applying the timezone offset to the DateTime fields in each record.解决方案是先读入记录,然后遍历它们,将时区偏移量应用到每条记录中的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;
}

It works nicely though, and this code is really useful when writing a web service to display date/times to users in different parts of the world.不过,它运行良好,并且在编写 Web 服务以向世界不同地区的用户显示日期/时间时,此代码非常有用。

Right now, I'm writing this article at 11am Zurich time, but if you were reading it in Los Angeles, you'd see that I edited it at 2am (your local time).现在,我在苏黎世时间上午 11 点写这篇文章,但如果你在洛杉矶阅读它,你会看到我在凌晨 2 点(你的当地时间)编辑它。 Using code like this, you can get your webpages to show date times that make sense to international users of your website.使用这样的代码,您可以让您的网页显示对您网站的国际用户有意义的日期时间。

Phew.呼。

Hope this helps.希望这可以帮助。

This isn't possible server side unless you assume it via the users ip address or get the user to set it in some form of a profile.这是不可能的服务器端,除非您通过用户 ip 地址假设它或让用户以某种形式的配置文件设置它。 You could get the clients time via javascript.您可以通过 javascript 获取客户时间。

See here for the javacript solution: Getting the client's timezone in JavaScript有关 javacript 解决方案,请参见此处: Getting the client's timezone in JavaScript

I got the same issue , Unfortunately there is no way for the server to know the client timezone .我遇到了同样的问题,不幸的是,服务器无法知道客户端时区。 If you want you can send client timezone as header while making ajax call .如果您愿意,可以在进行 ajax 调用时将客户端时区作为标头发送。

In-case if you want more info on adding the header this post may help how to add header to request : How can I add a custom HTTP header to ajax request with js or jQuery?如果您想了解有关添加标头的更多信息,这篇文章可能有助于如何向请求添加标头: 如何使用 js 或 jQuery 向 ajax 请求添加自定义 HTTP 标头?

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

If you don't want to add header every time , you can think of setting a cookie since cookie is sent with all httpRequest you can process the cookie to get client timezone on server side .如果您不想每次都添加标头,则可以考虑设置 cookie,因为 cookie 是随所有 httpRequest 一起发送的,您可以处理 cookie 以获取服务器端的客户端时区。 But i don't prefer adding cookies , for the same reason they sent with all http requests.但我不喜欢添加 cookie,原因与它们随所有 http 请求一起发送的原因相同。 Thanks.谢谢。

You will need to use both client-side and server-side technologies.您将需要同时使用客户端和服务器端技术。

On the client side:在客户端:
(pick one) (选一个)

  • This works in most modern browsers:这适用于大多数现代浏览器:

     Intl.DateTimeFormat().resolvedOptions().timeZone
  • There is also jsTimeZoneDetect 's jstz.determine() , or Moment-Timezone 's moment.tz.guess() function for older browsers, thought these libraries are generally only used in older applications.还有jsTimeZoneDetectjstz.determine()矩时区moment.tz.guess()对旧版浏览器的功能,认为这些库一般只在旧的应用程序使用。

The result from either will be an IANA time zone identifier , such as America/New_York .两者的结果将是IANA 时区标识符,例如America/New_York Send that result to the server by any means you like.以您喜欢的任何方式将该结果发送到服务器。

On the server side:在服务器端:
(pick one) (选一个)

  • Using TimeZoneInfo (on Non-Windows systems only):使用TimeZoneInfo (仅限非 Windows 系统):

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

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

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

For Dot Net version 3.5 and higher you can use :对于 Dot Net 3.5 及更高版本,您可以使用:

TimeZoneInfo.Local.GetUtcOffset(DateTime.UtcNow);

but for Dot Net lower than version 3.5 you can handle it manually via this way :但是对于低于 3.5 版的 Dot Net,您可以通过这种方式手动处理它:

first, get Offset from the client and store it in the cookie首先,从客户端获取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();
    }
}

} }

after that you can use a cookie in backend code like that :之后,您可以像这样在后端代码中使用 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();
}

I know the user asked about a non-javascript solution, but I wanted to post a javascript solution that I came up with.我知道用户询问了非 javascript 解决方案,但我想发布一个我想出的 javascript 解决方案。 I found some js libraries (jsTimezoneDetect, momentjs), but their output was an IANA code, which didn't seem to help me with getting a TimeZoneInfo object in C#.我找到了一些 js 库(jsTimezoneDetect、momentjs),但它们的输出是 IANA 代码,这似乎没有帮助我在 C# 中获取 TimeZoneInfo 对象。 I borrowed ideas from jsTimezoneDetect.我借鉴了 jsTimezoneDetect 的想法。 In javascript, I get the BaseUtcOffset and the first day of DST and send to server.在 javascript 中,我获取 BaseUtcOffset 和 DST 的第一天并发送到服务器。 The server then converts this to a TimeZoneInfo object.然后服务器将其转换为 TimeZoneInfo 对象。

Right now I don't care if the client Time Zone is chosen as "Pacific Time (US)" or "Baja California" for example, as either will create the correct time conversions (I think).现在我不在乎客户时区是否被选择为“太平洋时间(美国)”或“下加利福尼亚”,因为两者都会创建正确的时间转换(我认为)。 If I find multiple matches, I currently just pick the first found TimeZoneInfo match.如果我找到多个匹配项,我目前只选择第一个找到的 TimeZoneInfo 匹配项。

I can then convert my UTC dates from the database to local time:然后我可以将我的 UTC 日期从数据库转换为本地时间:

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

Javascript 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# 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;

You can get this information from client to server (any web API call)您可以从客户端到服务器获取此信息(任何 Web API 调用)

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

With the help of timezoneoffset details you can achieve the same.借助timezoneoffset详细信息,您可以实现相同的目标。 Here in my case i converted UTC DateTime to my client local datetime in Server side.在我的情况下,我将 UTC DateTime 转换为服务器端的客户端本地日期时间。

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

Click for code example点击代码示例

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM