你能从请求变量中确定时区吗?

34

有没有一种在服务器端读取HTTP请求中的内容来执行时区偏移操作的方法,而不是将所有内容发送到客户端并由其处理?

5个回答

23

这更加复杂,但我之前不得不使用这种情况,因为机器和用户配置有时与访问者的偏好不匹配。例如,从澳大利亚服务器暂时访问您的站点的英国访问者。

  1. 使用地理位置服务(例如MaxMind.com),如@balabaster建议的那样,获取与其IP匹配的时区(Global.Session_Start最佳)。这对于本地ISP来说是很好的匹配,但对于AOL来说则不太好。将此偏移量存储在会话cookie中。

  2. 或使用JavaScript在用户进入站点时作为表单提交/重定向的一部分获取时区偏移量。这是浏览器的当前偏移量,但是不一定是访问者首选的区域。使用此值作为默认值;在另一个会话cookie中存储。

  3. 
    <script type="text/javascript" language="JavaScript">
    var offset = new Date();
    document.write('<input type="hidden" id="clientTzOffset" name="clientTzOffset" value="' + offset.getTimezoneOffset() + '"/>');
    </script>
    
  4. 允许访客通过一个持久性cookie(针对匿名用户)和他们账户配置文件中的一个字段(认证用户)来更新区域。

来自#3的持久值优先于会话值。您还可以为验证用户存储相同的持久性cookie,以便在登录前显示时间。


0
有没有一种方法可以在服务器端执行您的时区偏移量,通过读取http请求中的某些内容,而不是将所有内容发送到客户端并让其处理?
以下是我解决WCF Web服务相同问题时想出的解决方案: 如何使WCF Web服务返回用户本地时区的日期时间 基本上,我让我的JavaScript / Angular代码确定用户的时区,然后将此值传递给我的WCF Web服务之一。
请注意,我有一个名为“getListOfRecords”的Web服务,它接受一个参数,即时区偏移值。
$scope.loadSomeDatabaseRecords = function () {

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

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

接下来,我的C#代码读取数据库记录,将时区偏移应用于UTC DateTime值,并将其返回给客户端。


我遇到了另一个问题,这使得它更加复杂。如果它只是使用偏移量来返回我的时区中下一年12月的日期,那么许多时区将匹配,而大多数时区不使用夏令时。 - DevelopingChris

0
我们可以在服务器端使用以下代码获取时区,而不是从客户端发送值。
private TimeZoneInfo GetRequestTimeZone()
    {
        TimeZoneInfo timeZoneInfo = null;
        DateTimeOffset localDateOffset;
        try
        {
            localDateOffset = new DateTimeOffset(Request.RequestContext.HttpContext.Timestamp, Request.RequestContext.HttpContext.Timestamp - Request.RequestContext.HttpContext.Timestamp.ToUniversalTime());
            timeZoneInfo = (from x in TimeZoneInfo.GetSystemTimeZones()
                            where x.BaseUtcOffset == localDateOffset.Offset
                            select x).FirstOrDefault();
        }
        catch (Exception)
        {
        }
        return timeZoneInfo;
    }

谢谢...


1
你尝试过在服务器设置为UTC,客户端设置为你实际时区的情况下运行吗? - DevelopingChris
3
你引起了我的兴趣,让我浪费了几分钟的时间来测试这个,但很抱歉,不能满足你的要求。这是一个有趣的概念。如果浏览器默认在请求头中发送本地时间就好了。 - johnw182
这似乎只是一种迂回的方式来确定服务器的时区,而可以更简单地实现。 - Chris Moschini

0
在页面卸载之前的任何事件中...使用Request.ServerVariables。如果您想要他们的物理时区,则检查其IP地址并使用IP到地理位置转换工具。
我不确定是否还有其他方法可以做到这一点,因此,如果您需要计算机配置的时区,则必须等待JavaScript加载页面...

4
谢谢你创造了我今天听到的最长的"不"。 - DevelopingChris
我曾经想知道为什么每次我用手机上的Opera Mini浏览网页时,都会看到针对挪威奥斯陆的本地化广告,后来我才意识到这是由于IP地址转换成地理位置所致...恰好奥斯陆距离我的居住地有几个时区的差距 :-) - Kaniu
ChanChan:你可以随时依靠我 ;) - BenAlabaster

0

这是我使用JavaScript和MVC解决它的方法:

首先,在主站点脚本中,我添加了以下代码:

var clientOffset = getCookie("_clientOffset");
var currentOffset = new Date().getTimezoneOffset() * -1;
var reloadForCookieRefresh = false;

if (clientOffset  == undefined || clientOffset == null || clientOffset != currentOffset) {
    setCookie("_clientOffset", currentOffset, 30);
    reloadForCookieRefresh = true;
}

if (reloadForCookieRefresh)
    window.location.reload();

function setCookie(name, value, days) {
    var expires = "";
    if (days) {
        var date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        expires = "; expires=" + date.toUTCString();
    }
    document.cookie = name + "=" + (value || "") + expires + "; path=/";
}

function getCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for (var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') c = c.substring(1, c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
    }
    return null;
}

在服务器端的操作过滤器中:

public class SetCurrentRequestDataFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        // currentRequestService is registered by request using IoC container
        var currentRequestService = iocResolver.Resolve<ICurrentRequestService>();

        if (context.HttpContext.Request.Cookies.AllKeys.Contains("_clientOffset"))
        {
            currentRequestService.ClientOffset = int.Parse(context.HttpContext.Request.Cookies.Get("_clientOffset").Value);
        }

    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接