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

时间:2011-11-19 12:21:49

标签: c# asp.net asp.net-mvc-3

我正在MVC3中构建一个应用程序,当用户进入我的网站时,我想知道该用户的时区。我想知道如何在c#而不是javaScript中执行此操作?

9 个答案:

答案 0 :(得分:19)

除非您通过用户IP地址假设它或让用户以某种形式的配置文件设置它,否则这不可能是服务器端。你可以通过javascript获得客户的时间。

请参阅此处了解javacript解决方案:Getting the client's timezone in JavaScript

答案 1 :(得分:19)

如前所述,您需要您的客户端告诉您的ASP.Net服务器有关他们所在的时区的详细信息。

这是一个例子。

我有一个Angular控制器,它以JSON格式从我的SQL Server数据库加载记录列表。问题是,这些记录中的DateTime值是UTC时区,我想向用户显示当地时区的日期/时间。

我使用JavaScript“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点(当地时间)编辑了它。使用这样的代码,您可以让您的网页显示对您网站的国际用户有意义的日期时间。

呼。

希望这会有所帮助。

答案 2 :(得分:6)

我遇到了同样的问题,不幸的是服务器无法知道客户端时区。 如果你想要,你可以在进行ajax调用时发送客户端时区作为标题。

如果您想了解有关添加标题的更多信息,请点击此帖子可能有助于如何添加标题以供请求:How can I add a custom HTTP header to ajax request with js or jQuery?

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

如果你不想每次都添加标题,你可以考虑设置一个cookie,因为cookie是与所有httpRequest一起发送的,你可以处理cookie以获得服务器端的客户端时区。但我不喜欢添加cookie,原因与他们发送所有http请求的原因相同。 感谢。

答案 3 :(得分:3)

我知道用户询问了非JavaScript的解决方案,但我想发布一个我想出的javascript解决方案。我找到了一些js库(jsTimezoneDetect,momentjs),但它们的输出是一个IANA代码,它似乎无助于我在C#中获取TimeZoneInfo对象。我从jsTimezoneDetect借用了一些想法。在javascript中,我获得了BaseUtcOffset和DST的第一天并发送到服务器。然后,服务器将其转换为TimeZoneInfo对象。

现在我不在乎客户时区被选为&#34;太平洋时间(美国)&#34;或者&#34;下加利福尼亚州&#34;例如,任何一个都会创建正确的时间转换(我认为)。如果我找到多个匹配项,我目前只选择第一个找到的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];
    }

答案 4 :(得分:1)

您将需要同时使用客户端和服务器端技术。

在客户端:
(选择一个)

  • 这适用于大多数现代浏览器:

    Intl.DateTimeFormat().resolvedOptions().timeZone
    
  • 对于较旧的浏览器,还有jsTimeZoneDetectjstz.determine()Moment-Timezonemoment.tz.guess()函数。

任何一个的结果都是IANA time zone identifier,例如America/Los_Angeles。通过您喜欢的任何方式将该结果发送到服务器。

在服务器端:
(选择一个)

  • 使用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"];
    

答案 5 :(得分:0)

对于Dot Net 3.5及更高版本,您可以使用:

TimeZoneInfo.Local.GetUtcOffset(DateTime.UtcNow);

但是对于Dot Net在版本3.5下,您可以通过以下方式手动处理它:

首先从客户端获取Offset并将其存储在cookie

function setTimezoneCookie(){

var timezone_cookie = "timezoneoffset";

// if the timezone cookie not exists 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();
}

答案 6 :(得分:0)

看看这个asp.net c#解决方案

TimeZoneInfo mytzone = TimeZoneInfo.Local;

答案 7 :(得分:0)

您可以从客户端到服务器(任何 Web API 调用)获取此信息

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

timezoneoffset 详细信息的帮助下,您可以实现相同的目标。在我的情况下,我将 UTC DateTime 转换为服务器端的客户端本地日期时间。

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

Click for code example

答案 8 :(得分:-2)

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