【问题标题】:Determine a user's timezone确定用户的时区
【发布时间】:2014-05-02 07:41:33
【问题描述】:

网络服务器是否有一种标准方法可以确定网页中用户的时区?

可能来自 HTTP 标头或 user-agent 字符串的一部分?

【问题讨论】:

  • 询问用户。如果你从用户的电脑上得到时区,而且设置错了,那怎么办?
  • 那么用户可能不在乎?
  • 你的意思是stackoverflow.com/q/1091372/218196 吗?
  • 不幸的是,这个问题的答案还允许用户分析和地理围栏。
  • 为什么需要知道用户时区?

标签: html browser timezone user-agent timezone-offset


【解决方案1】:

有几种方法可以确定浏览器中的时区。如果您的浏览器有可用且支持的标准功能,那么您应该使用该功能。以下是以不同格式获取相同信息的三种方法。避免使用基于某些假设或硬编码区域列表进行任何猜测的非标准解决方案,尽管如果无法采取其他措施,它们可能会有所帮助。

获得此信息后,您可以将其作为非标准请求标头传递给服务器并在那里使用。如果您还需要时区偏移量,您还可以将其传递给服务器的标头或请求有效负载,可以使用 dateObj.getTimezoneOffset() 检索。

  1. 使用 Intl API 获取 Olson 格式(标准和推荐方式):请注意,并非所有浏览器都支持。有关浏览器对此支持的详细信息,请参阅 this link。 这个 API 让您可以获取 Olson 格式的时区,例如 Asia/Kolkata、America/New_York 等。

Intl.DateTimeFormat().resolvedOptions().timeZone
  1. 使用 Date 对象获取长格式,例如印度标准时间、东部标准时间等:所有浏览器都支持。

let dateObj = new Date(2021, 11, 25, 09, 30, 00);

//then 

dateObj.toString() 

//yields

Sat Dec 25 2021 09:30:00 GMT+0530 (India Standard Time) //I am located in India (IST)

请注意,该字符串包含长短格式的时区信息。您现在可以使用正则表达式来获取此信息:

let longZoneRegex = /\((.+)\)/;
dateObj.toString().match(longZoneRegex);

//yields

['(India Standard Time)', 'India Standard Time', index: 34, input: 'Sat Dec 25 2021 09:30:00 GMT+0530 (India Standard Time)', groups: undefined]

//Note that output is an array so use output[1] to get the timezone name.
  1. 使用 Date 对象获取短格式,例如 GMT+0530、GMT-0500 等:所有浏览器都支持。

同样,你也可以得到短格式:

let shortZoneRegex = /GMT[+-]\d{1,4}/;
dateObj.toString().match(shortZoneRegex);

//yields

['GMT+0530', index: 25, input: 'Sat Dec 25 2021 09:30:00 GMT+0530 (India Standard Time)', groups: undefined]

//Note that output is an array so use output[0] to get the timezone name.

【讨论】:

    【解决方案2】:

    我认为@Matt Johnson-Pints 是迄今为止最好的,CanIuse 搜索显示它现在已被广泛采用:

    https://caniuse.com/?search=Intl.DateTimeFormat().resolvedOptions().timeZone

    但其中一个挑战是考虑您为什么想知道时区。因为我认为大多数人错过的一件事是他们可以改变!如果用户带着他的笔记本电脑从欧洲旅行到美国,如果你以前将它存储在数据库中,那么他们的时区现在不正确(即使用户从未真正更新他们的设备时区)。这也是@Mads Kristiansen 答案的问题,因为用户旅行 - 你不能依赖它作为给定的。

    例如,我的 Linux 笔记本电脑已关闭“自动时区”。虽然时间可能会更新我的时区,但不会。

    所以我相信答案是 - 你需要它做什么?客户端当然似乎提供了一种更简单的方法来确定它,但是客户端和服务器端代码都将取决于用户更新他们的时区还是自动更新。我当然可能是错的。

    【讨论】:

      【解决方案3】:

      这是一个强大的 JavaScript 解决方案,用于确定浏览器所在的时区。

      >>> var timezone = jstz.determine();
      >>> timezone.name(); 
      "Europe/London"
      

      https://github.com/pellepim/jstimezonedetect

      【讨论】:

      • 不鼓励仅链接答案,因为如果链接消失,答案将不再有用;并且因为不点击链接,读者不知道它是否给出了一个好的答案。在这种情况下,您可以澄清这是一个第三方库,它采用基于数据库的方法进行识别,并可能解释其一些操作原理。
      • 这个!这是要走的路。简单的库,正确处理 DST。其他答案充满了WTF,许多人不做DST。
      • 这个库非常聪明。它的工作原理是查询当前与 UTC 的偏移量,然后通过添加或减去秒数来调整 JavaScript Date 对象时间,直到与 UTC 的偏移量发生变化。使用这种方法,这个库计算出足够多的 DST 更改来唯一标识时区。我认为如果该库进行二进制搜索而不是线性搜索,它的性能可能会更好。返回值是一个 IANA 区域信息键(又名奥尔森时区数据库)。
      • 不再需要这个库。现代浏览器支持 Intl API,它返回 IANA 时区字符串。见this answer
      【解决方案4】:

      首先,了解 JavaScript 中的时区检测是不完善的。您可以在 Date 对象的实例上使用 getTimezoneOffset 获取特定日期和时间的本地时区偏移,但这与完整的 IANA time zone 不太一样,例如 @987654332 @。

      有一些选项可以工作:

      const tzid = Intl.DateTimeFormat().resolvedOptions().timeZone;
      console.log(tzid);

      结果是一个字符串,其中包含运行代码的计算机的 IANA 时区设置。

      列出了支持的环境in the Intl compatibility table。展开DateTimeFormat 部分,查看名为resolvedOptions().timeZone defaults to the host environment 的功能。

      • 一些库,如Luxon 使用此API 通过luxon.Settings.defaultZoneName 等函数来确定时区。

      • 如果您需要支持更广泛的环境集,例如较旧的网络浏览器,您可以使用库在时区进行有根据的猜测。他们首先尝试Intl API(如果可用),当它不可用时,他们会在几个不同的时间点询问Date 对象的getTimezoneOffset 函数,使用结果来选择合适的时区来自内部数据集。

        jsTimezoneDetectmoment-timezone 都具有此功能。

          // using jsTimeZoneDetect
          var tzid = jstz.determine().name();
        
          // using moment-timezone
          var tzid = moment.tz.guess();
        

        在这两种情况下,结果只能被认为是猜测。在许多情况下,猜测可能是正确的,但并非所有情况。

        此外,这些库必须定期更新,以抵消许多较旧的 JavaScript 实现只知道其本地时区的当前夏令时规则的事实。 More details on that here.

      最终,更好的方法是实际询问您的用户他们的时区。提供他们可以更改的设置。您可以使用上述选项之一来选择 默认 设置,但不要让您的应用无法偏离该设置。

      还有完全不同的方法完全依赖用户计算机的时区设置。相反,如果您可以收集纬度和经度坐标,则可以使用 one of these methods 将它们解析为时区。这在移动设备上运行良好。

      【讨论】:

      • 使用用户的地理位置(即他们的语言环境)来推断时区也是有缺陷的。用户可能希望在他们的设备上使用不是本地时区的特定时区,即使它可能会显示相同的时间(或不显示相同的时间)。例如。旅行者经常将他们的设备时区设置为他们通常的位置,并且不希望在没有得到建议的情况下看到日期和时间使用不同的偏移量。我可能是从这里的个人经历说的...... ;-)
      • 不知道你是不是在骗我 Rob。 ;) 但是这些方法都没有使用它们的语言环境,而是使用设备上的设置,因此与您的观点一致。 (只有上一段中提到的替代方法会使用当前位置。)
      • 附上一个术语说明:“locale”强调不是用户的地理位置。 “区域设置”是一组设置,例如语言、数字格式、日历等。例如,de_DE 区域设置指定德语为默认语言,欧元为默认货币,逗号为小数分隔符,句点为千位分隔符,公历作为日历。见developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
      【解决方案5】:

      没有办法在实际的 HTML 代码或任何user-agent 字符串中计算时区,但您可以做一个使用 JavaScript 获取它的基本函数。

      我还不知道如何使用 JavaScript 编写代码,所以我的函数可能需要一些时间来完成。

      但是,您也可以尝试在 Date 部分中使用带有 getTzimezoneOffset() 函数的 JavaScript 或简单地使用 new Date().getTimezoneOffset(); 来获取实际时区。

      【讨论】:

        【解决方案6】:

        所有的魔法似乎都在

        visitortime.getTimezoneOffset()
        

        这很酷,我不知道。它可以在 Internet Explorer 等中使用吗?从那里你应该能够使用 JavaScript 到 Ajax,设置任何 cookie。我可能会自己走 cookie 路线。

        您需要允许用户更改它。不久前,我们尝试使用地理位置(通过maxmind)来执行此操作,但它是错误的,以至于不值得这样做。所以我们只是让用户在他们的个人资料中设置它,并向尚未设置的用户显示通知。

        【讨论】:

          【解决方案7】:

          在 PHP 中获取有效的 TZ 数据库时区名称是一个两步过程:

          1. 使用 JavaScript,通过getTimezoneOffset 以分钟为单位获取时区偏移量。如果本地时区落后于 UTC,则此偏移量将为正数,如果早于 UTC,则此偏移量将为负数。所以你必须在偏移量上添加一个相反的符号。

            var timezone_offset_minutes = new Date().getTimezoneOffset();
            timezone_offset_minutes = timezone_offset_minutes == 0 ? 0 : -timezone_offset_minutes;
            

            将此偏移量传递给 PHP。

          2. 在 PHP 中,使用 timezone_name_from_abbr 函数将此偏移量转换为有效的时区名称。

            // Just an example.
            $timezone_offset_minutes = -360;  // $_GET['timezone_offset_minutes']
            
            // Convert minutes to seconds
            $timezone_name = timezone_name_from_abbr("", $timezone_offset_minutes*60, false);
            
            // America/Chicago
            echo $timezone_name;</code></pre>
            

          我在上面写了一篇博文:How to Detect User Timezone in PHP。它还包含一个演示。

          【讨论】:

          【解决方案8】:

          您可以在客户端使用moment-timezone 执行此操作并将值发送到服务器;示例用法:

          > moment.tz.guess()
          "America/Asuncion"
          

          【讨论】:

          【解决方案9】:

          使用 JavaScript 和 PHP 很简单:

          尽管用户可能会弄​​乱他/她的内部时钟和/或时区,但到目前为止我找到的获得偏移量的最佳方法仍然是 new Date().getTimezoneOffset();。它是非侵入性的,不会让人头疼,并且无需依赖第三方。

          假设我有一个表 users,其中包含一个字段 date_created int(13),用于存储 Unix 时间戳;

          假设客户端creates a new account,数据由post接收,我需要insert/updatedate_created column带有客户端的Unix时间戳,而不是服务器的。

          由于在插入/更新时需要 timezoneOffset,因此在客户端提交表单时将其作为额外的 $_POST 元素传递,从而无需将其存储在会话和/或 cookie 中,也无需额外的服务器命中。

          var off = (-new Date().getTimezoneOffset()/60).toString();//note the '-' in front which makes it return positive for negative offsets and negative for positive offsets
          var tzo = off == '0' ? 'GMT' : off.indexOf('-') > -1 ? 'GMT'+off : 'GMT+'+off;
          

          假设服务器接收tzo$_POST['tzo']

          $ts = new DateTime('now', new DateTimeZone($_POST['tzo']);
          $user_time = $ts->format("F j, Y, g:i a");//will return the users current time in readable format, regardless of whether date_default_timezone() is set or not.
          $user_timestamp = strtotime($user_time);
          

          插入/更新date_created=$user_timestamp

          在检索 date_created 时,您可以像这样转换时间戳:

          $date_created = // Get from the database
          $created = date("F j, Y, g:i a",$date_created); // Return it to the user or whatever
          

          现在,此示例可能适合您的需求,当涉及到插入 first 时间戳时......当涉及到额外的时间戳或表时,您可能需要考虑将 tzo 值插入到 users 表中未来参考,或将其设置为会话或 cookie。

          附:但是,如果用户旅行并切换时区怎么办。在 GMT+4 登录,快速到达 GMT-1 并再次登录。上次登录将在将来。

          我认为……我们想太多了。

          【讨论】:

            【解决方案10】:

            不要使用 IP 地址来明确确定位置(因此也确定时区)——这是因为对于 NAT、代理(越来越流行)和 VPN,IP 地址不一定真实地反映用户的实际位置,而是位置实现这些协议的服务器所在的位置。

            鉴于号码可携带性的普及,类似于美国区号不再用于定位电话用户。

            上面显示的 IP 地址和其他技术对于建议用户可以调整/更正的默认值很有用。

            【讨论】:

              【解决方案11】:

              试试这个 PHP 代码:

              <?php
                  $ip = $_SERVER['REMOTE_ADDR'];
                  $json = file_get_contents("http://api.easyjquery.com/ips/?ip=" . $ip . "&full=true");
                  $json = json_decode($json,true);
                  $timezone = $json['LocalTimeZone'];
              ?>
              

              【讨论】:

                【解决方案12】:

                JavaScript:

                function maketimus(timestampz)
                {
                    var linktime = new Date(timestampz * 1000);
                    var linkday = linktime.getDate();
                    var freakingmonths = new Array();
                
                    freakingmonths[0]  = "jan";
                    freakingmonths[1]  = "feb";
                    freakingmonths[2]  = "mar";
                    freakingmonths[3]  = "apr";
                    freakingmonths[4]  = "may";
                    freakingmonths[5]  = "jun";
                    freakingmonths[6]  = "jul";
                    freakingmonths[7]  = "aug";
                    freakingmonths[8]  = "sep";
                    freakingmonths[9]  = "oct";
                    freakingmonths[10] = "nov";
                    freakingmonths[11] = "dec";
                
                    var linkmonthnum = linktime.getMonth();
                    var linkmonth = freakingmonths[linkmonthnum];
                    var linkyear = linktime.getFullYear();
                    var linkhour = linktime.getHours();
                    var linkminute = linktime.getMinutes();
                
                    if (linkminute < 10)
                    {
                        linkminute = "0" + linkminute;
                    }
                
                    var fomratedtime = linkday + linkmonth + linkyear + " " +
                                       linkhour + ":" + linkminute + "h";
                    return fomratedtime;
                }
                

                只需向该函数提供 Unix 时间戳格式的时间; JavaScript 已经知道用户的时区。

                像这样:

                PHP:

                echo '<script type="text/javascript">
                var eltimio = maketimus('.$unix_timestamp_ofshiz.');
                document.write(eltimio);
                </script><noscript>pls enable javascript</noscript>';
                

                这将始终根据用户在他/她的计算机时钟上设置的时区正确显示时间。无需向任何人询问任何内容并将其保存到地方,感谢上帝!

                【讨论】:

                • $unix_timestamp_ofshiz ?这里缺少一些东西并且不太有效,即使这看起来可能是一个很好的答案。
                【解决方案13】:

                使用 Unkwntech 的方法,我使用 jQuery 和 PHP 编写了一个函数。这是经过测试并且确实有效!

                在您希望将时区作为变量的 PHP 页面上,将这段代码 sn-p 放在页面顶部附近的某处:

                <?php
                    session_start();
                    $timezone = $_SESSION['time'];
                ?>
                

                这将读取我们现在要创建的会话变量“time”。

                在同一个页面中,在

                中,首先需要包含jQuery:
                <script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
                

                同样在

                的 jQuery 下方,粘贴以下内容:
                <script type="text/javascript">
                    $(document).ready(function() {
                        if("<?php echo $timezone; ?>".length==0){
                            var visitortime = new Date();
                            var visitortimezone = "GMT " + -visitortime.getTimezoneOffset()/60;
                            $.ajax({
                                type: "GET",
                                url: "http://example.org/timezone.php",
                                data: 'time='+ visitortimezone,
                                success: function(){
                                    location.reload();
                                }
                            });
                        }
                    });
                </script>
                

                您可能注意到也可能没有注意到,但您需要将 URL 更改为您的实际域。

                最后一件事。您可能想知道 timezone.php 到底是什么。嗯,就是这样: (创建一个名为 timezone.php 的新文件并用上面的 URL 指向它)

                <?php
                    session_start();
                    $_SESSION['time'] = $_GET['time'];
                ?>
                

                如果这工作正常,它将首先加载页面,执行 JavaScript,然后重新加载页面。然后,您将能够读取 $timezone 变量并随意使用它!它返回当前的 UTC/GMT 时区偏移量 (GMT -7) 或您所在的任何时区。

                【讨论】:

                • 我喜欢这样,但我可能有一些东西可以检查当前的 $_SESSION['time'] 并且只有在不同时才能重新加载 javascript
                • 使用 Cookie 可能比使用 Session 来传输它更容易,因为锁定和反序列化 PHP 会话可能会导致应用程序变慢。为了获得最大效率,您可以将值复制到会话中并删除 cookie,以便它不会在后续请求中发送。
                【解决方案14】:

                这里有一个更完整的方法。

                1. 获取用户的时区偏移量
                2. 在夏令时边界上测试几天,以确定它们是否在使用夏令时的区域内。

                摘录如下:

                function TimezoneDetect(){
                    var dtDate = new Date('1/1/' + (new Date()).getUTCFullYear());
                    var intOffset = 10000; //set initial offset high so it is adjusted on the first attempt
                    var intMonth;
                    var intHoursUtc;
                    var intHours;
                    var intDaysMultiplyBy;
                
                    // Go through each month to find the lowest offset to account for DST
                    for (intMonth=0;intMonth < 12;intMonth++){
                        //go to the next month
                        dtDate.setUTCMonth(dtDate.getUTCMonth() + 1);
                
                        // To ignore daylight saving time look for the lowest offset.
                        // Since, during DST, the clock moves forward, it'll be a bigger number.
                        if (intOffset > (dtDate.getTimezoneOffset() * (-1))){
                            intOffset = (dtDate.getTimezoneOffset() * (-1));
                        }
                    }
                
                    return intOffset;
                }
                

                Getting TZ and DST from JS(通过 Way Back Machine)

                【讨论】:

                • 这对我有用!阅读博文下的 cmets 以获取代码的一些更新。
                • 这仍然只会返回时区的标准偏移量,例如+02:00。它不会为您提供足够的信息来确定用户的时区,例如Africa/JohannesburgEurope/Istanbul。见the timezone tag wiki
                【解决方案15】:

                使用 PHP date 函数,您将获得站点所在服务器的日期时间。获得用户时间的唯一方法是使用 JavaScript。

                但我建议您这样做,如果您的网站需要注册,那么最好的方法是询问用户,同时将注册作为必填字段。您可以在注册页面中列出各种时区并将其保存在数据库中。在此之后,如果用户登录到站点,那么您可以根据用户选择的时区设置该会话的默认时区。

                您可以使用 PHP 函数 date_default_timezone_set 设置任何特定的时区。这会为用户设置指定的时区。

                基本上用户的时区是到客户端的,所以我们必须使用 JavaScript。

                以下是使用 PHP 和 JavaScript 获取用户时区的脚本。

                <?php
                    #http://www.php.net/manual/en/timezones.php List of Time Zones
                    function showclienttime()
                    {
                        if(!isset($_COOKIE['GMT_bias']))
                        {
                ?>
                
                            <script type="text/javascript">
                                var Cookies = {};
                                Cookies.create = function (name, value, days) {
                                    if (days) {
                                        var date = new Date();
                                        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
                                        var expires = "; expires=" + date.toGMTString();
                                    }
                                    else {
                                        var expires = "";
                                    }
                                    document.cookie = name + "=" + value + expires + "; path=/";
                                    this[name] = value;
                                }
                
                                var now = new Date();
                                Cookies.create("GMT_bias",now.getTimezoneOffset(),1);
                                window.location = "<?php echo $_SERVER['PHP_SELF'];?>";
                            </script>
                
                            <?php
                
                        }
                        else {
                          $fct_clientbias = $_COOKIE['GMT_bias'];
                        }
                
                        $fct_servertimedata = gettimeofday();
                        $fct_servertime = $fct_servertimedata['sec'];
                        $fct_serverbias = $fct_servertimedata['minuteswest'];
                        $fct_totalbias = $fct_serverbias – $fct_clientbias;
                        $fct_totalbias = $fct_totalbias * 60;
                        $fct_clienttimestamp = $fct_servertime + $fct_totalbias;
                        $fct_time = time();
                        $fct_year = strftime("%Y", $fct_clienttimestamp);
                        $fct_month = strftime("%B", $fct_clienttimestamp);
                        $fct_day = strftime("%d", $fct_clienttimestamp);
                        $fct_hour = strftime("%I", $fct_clienttimestamp);
                        $fct_minute = strftime("%M", $fct_clienttimestamp);
                        $fct_second = strftime("%S", $fct_clienttimestamp);
                        $fct_am_pm = strftime("%p", $fct_clienttimestamp);
                        echo $fct_day.", ".$fct_month." ".$fct_year." ( ".$fct_hour.":".$fct_minute.":".$fct_second." ".$fct_am_pm." )";
                    }
                
                    showclienttime();
                ?>
                

                但根据我的观点,最好询问用户在您的项目中是否必须注册。

                【讨论】:

                  【解决方案16】:

                  JavaScript 是获取客户端本地时间的最简单方法。我建议使用XMLHttpRequest 发回本地时间,如果失败,则回退到根据其 IP 地址检测到的时区。

                  就地理位置而言,我在几个项目中使用了MaxMind GeoIP,它运行良好,但我不确定它们是否提供时区数据。这是一项您需要付费的服务,他们会为您的数据库提供每月更新。它们提供多种网络语言的包装器。

                  【讨论】:

                  • 我投票赞成这个答案,因为从 GeoIP(目前有免费版本)等数据库获得的纬度和经度可以与将此类坐标转换为时区的数据库结合使用。我认为 GeoNames 有后者这样的数据库。
                  • MaxMind GeoIP 数据库/API 的当前版本(免费和付费)确实提供了时区信息(它为我的时区返回“欧洲/伦敦”。)我不记得了他们的GeoIP系统的旧版本是否也做了同样的事情,但现在效果很好! MaxMind 字段被命名为“time_zone”、“time_zone_name”。
                  【解决方案17】:
                  -new Date().getTimezoneOffset()/60;
                  

                  getTimezoneOffset() 方法将从 GMT 中减去您的时间并返回分钟数。因此,如果您居住在 GMT-8,它将返回 480。

                  要将其转换为小时,请除以 60。另外,请注意符号与您需要的相反 - 它计算的是 GMT 与您的时区的偏移量,而不是您的时区与 GMT 的偏移量。要解决此问题,只需乘以 -1。

                  还要注意w3school 说:

                  返回值不是常量,因为使用的习惯 夏令时。

                  【讨论】:

                  • 那些使用没有javascript支持的浏览器的手机的用户呢?我喜欢这个问题,用户询问 HTTP 标头、用户代理……有没有办法让服务器端的工作尽可能准确?
                  • 这并不总是适用于 DST。获取时区偏移量正是它所说的。它得到的偏移量。时区实际上是一个地理区域。这不适用于夏令时,因为您不知道用户居住在哪个半球,或者他们的国家是否有夏令时。为什么不改用这个:&gt;&gt;&gt; date.toTimeString() "15:46:04 GMT+1200 (New Zealand Standard Time)"
                  • 我与 Keyo 不同。 getTimezoneOffset() 的定义(根据 ECMA 标准ecma-international.org/ecma-262/5.1/#sec-15.9.5.26)是“以分钟为单位返回本地时间和 UTC 时间之间的差异”。 - 换句话说,它应该考虑夏令时。 Mozilla 的文档说“夏令时可以防止这个值成为常数,即使对于给定的语言环境也是如此。”
                  • @xgretsch:它从 GMT 获取用户的 当前 偏移量。如果您要呈现同一天发生的另一个时间,那很好(除非当前日期是转换日期,这可能是错误的)。但是,有许多时区与 GMT 的偏移量相同,它们可能有不同的转换日期或不使用夏令时。
                  • 这里要注意的一点;有些地方(例如加拿大的纽芬兰)的时区相差半小时,因此除以 60 后,您的答案可能不是整数。
                  【解决方案18】:

                  这是一篇文章(附源代码),解释了如何在 ASP.NET(VB.NET、C#)应用程序中确定和使用本地化时间:

                  It's About Time

                  简而言之,所描述的方法依赖于 JavaScript getTimezoneOffset 函数,该函数返回保存在会话 cookie 中并由代码隐藏用于调整 GMT 和本地时间之间的时间值的值。好处是用户不需要指定时区(代码会自动指定)。涉及的内容更多(这就是我链接到该文章的原因),但提供的代码使其非常易于使用。我怀疑您可以将逻辑转换为 PHP 和其他语言(只要您了解 ASP.NET)。

                  【讨论】:

                  • 链接已失效。我认为这是替代链接:devproconnections.com/article/aspnet2/it-s-about-time-122778
                  • 该文章也可在此处以 PDF 格式提供:app.box.com/shared/bfvvmidtyg
                  • 本文描述的将UTC服务器时间转换为本地客户端时间的方法是错误的。使用当前客户端偏移量来调整服务器上的 UTC 时间将导致半年的不正确的“本地”时间用于遵守夏令时的客户端区域设置。考虑这种情况:英国的一位客户在 2013 年 1 月 14 日(GMT+0000 标准时间)将日期和时间设置为 2015 年 8 月 21 日 14:00(GMT+0100 夏令时间)。这在服务器上被标准化为 2015 年 8 月 21 日 13:00 UTC。在发生这种情况的那一天,客户端偏移量为 0,因此发送回客户端的时间将为 2015 年 8 月 21 日 13:00。
                  • 有效点,但我并没有声称这是一个防弹解决方案。如果您需要实施一个真正对时间敏感的解决方案,例如火车票预订应用程序,那么您需要找到一个更全面(和复杂的解决方案)。但是,对于许多应用程序来说,这不是问题。因为在许多情况下,我们希望本地化当前会话的 GMT 值。现在,如果您有一个应用程序需要在将来为某些时间保存时间戳并且它不能容忍 DTS,那么正确的方法是提供一个直接在 GMT 中节省时间的选项。如果您知道更好的选择,请分享。
                  【解决方案19】:

                  使用jQuery 将时区偏移量作为 HTTP 标头提交给 AJAX 请求

                  $.ajaxSetup({
                      beforeSend: function(xhr, settings) {
                          xhr.setRequestHeader("X-TZ-Offset", -new Date().getTimezoneOffset()/60);
                      }
                  });
                  

                  您还可以通过使用来自http://momentjs.com/timezone/docs/#/using-timezones/guessing-user-timezone/moment.tz.guess(); 执行类似的操作来获取实际时区名称

                  【讨论】:

                  • 这仅返回当前时区偏移量——而不是时区。见the timezone tag wiki
                  • 已编辑以包含有关对时区名称执行相同操作的信息。
                  【解决方案20】:

                  这就是我的做法。这会将 PHP 默认时区设置为用户的本地时区。只需将以下内容粘贴到所有页面的顶部:

                  <?php
                  session_start();
                  
                  if(!isset($_SESSION['timezone']))
                  {
                      if(!isset($_REQUEST['offset']))
                      {
                      ?>
                          <script>
                          var d = new Date()
                          var offset= -d.getTimezoneOffset()/60;
                          location.href = "<?php echo $_SERVER['PHP_SELF']; ?>?offset="+offset;
                          </script>
                          <?php   
                      }
                      else
                      {
                          $zonelist = array('Kwajalein' => -12.00, 'Pacific/Midway' => -11.00, 'Pacific/Honolulu' => -10.00, 'America/Anchorage' => -9.00, 'America/Los_Angeles' => -8.00, 'America/Denver' => -7.00, 'America/Tegucigalpa' => -6.00, 'America/New_York' => -5.00, 'America/Caracas' => -4.30, 'America/Halifax' => -4.00, 'America/St_Johns' => -3.30, 'America/Argentina/Buenos_Aires' => -3.00, 'America/Sao_Paulo' => -3.00, 'Atlantic/South_Georgia' => -2.00, 'Atlantic/Azores' => -1.00, 'Europe/Dublin' => 0, 'Europe/Belgrade' => 1.00, 'Europe/Minsk' => 2.00, 'Asia/Kuwait' => 3.00, 'Asia/Tehran' => 3.30, 'Asia/Muscat' => 4.00, 'Asia/Yekaterinburg' => 5.00, 'Asia/Kolkata' => 5.30, 'Asia/Katmandu' => 5.45, 'Asia/Dhaka' => 6.00, 'Asia/Rangoon' => 6.30, 'Asia/Krasnoyarsk' => 7.00, 'Asia/Brunei' => 8.00, 'Asia/Seoul' => 9.00, 'Australia/Darwin' => 9.30, 'Australia/Canberra' => 10.00, 'Asia/Magadan' => 11.00, 'Pacific/Fiji' => 12.00, 'Pacific/Tongatapu' => 13.00);
                          $index = array_keys($zonelist, $_REQUEST['offset']);
                          $_SESSION['timezone'] = $index[0];
                      }
                  }
                  
                  date_default_timezone_set($_SESSION['timezone']);
                  
                  //rest of your code goes here
                  ?>
                  

                  【讨论】:

                  • 这不考虑“夏令时”调整 - 都柏林的用户在冬天会匹配您的“欧洲/都柏林”,但在夏天会匹配“欧洲/贝尔格莱德”。如果您要使用当前的偏移量,您可以合理地假设是该偏移量,而不是地理标识符。
                  【解决方案21】:

                  一种可能的选择是使用Date 标头字段,该字段在RFC 7231 中定义并且应该包含时区。当然,不能保证该值确实是客户端的时区,但它可以是一个方便的起点。

                  【讨论】:

                  • 不幸的是,该标头似乎主要用于响应,而不是请求:“用户代理可以在请求中发送 Date 标头字段,但通常不会这样做,除非它被认为传达有用信息到服务器。”我刚查了一下,火狐没有发送。
                  【解决方案22】:

                  我见过的最流行的(==标准?)确定时区的方法是询问用户自己。如果您的网站需要订阅,可以将其保存在用户中' 个人资料数据。对于匿名用户,日期可以显示为 UTC 或 GMT 等。

                  我不想成为一个聪明的家伙。只是有时有些问题在任何编程环境之外都有更好的解决方案。

                  【讨论】:

                  • 当用户下载的 .ics 文件应该具有特定于其位置的开始时间(例如全国上午 9 点到 11 点)时,该怎么办?他们不应该说他们的时区是 imo。
                  • @Ishmaeel:但用户确实会出国旅行,他们不应该在每次从某个非本地时区登录时告诉他们的时区
                  • 这并没有回答问题,这显然意味着他正在寻找技术解决方案。
                  • @gWiz OP 要求提供标准解决方案。这是相当标准的。
                  • 最好的解决方案可能是结合询问用户(例如,在报告顶部提供时区下拉菜单),同时默认下拉选择为 GPS 确定的时间 -当用户使用提供位置信息的移动设备时的区域,否则默认为 UTC。
                  【解决方案23】:

                  简单,只需像这样使用 JavaScript getTimezoneOffset 函数:

                  -new Date().getTimezoneOffset()/60;
                  

                  【讨论】:

                  • 另外,它只返回当前时区偏移量——而不是时区。见the timezone tag wiki
                  • 这只是已接受答案的副本,为什么你还要投票。
                  【解决方案24】:

                  一个简单的方法是使用:

                  new Date().getTimezoneOffset();
                  

                  【讨论】:

                  【解决方案25】:

                  我仍然没有在这里看到获得时区的详细答案。您不需要按 IP 地址进行地理编码或使用 PHP (lol) 或错误地从偏移量猜测。

                  首先,时区不仅仅是与 GMT 的偏移量。这是一块土地,其时间规则由当地标准制定。一些国家有夏令时,并且会在不同的时间开启 DST。获取实际区域通常很重要,而不仅仅是当前偏移量。

                  如果您打算存储此时区,例如在用户首选项中,您需要该时区而不仅仅是偏移量。对于实时转换来说,这并不重要。

                  现在,要使用 javascript 获取时区,您可以使用:

                  >> new Date().toTimeString();
                  "15:46:04 GMT+1200 (New Zealand Standard Time)"
                  //Use some regular expression to extract the time.
                  

                  但是我发现简单地使用这个强大的插件会更容易,它会返回 Olsen 格式的时区:

                  https://github.com/scottwater/jquery.detect_timezone

                  【讨论】:

                    【解决方案26】:

                    如果您碰巧使用OpenID 进行身份验证,Simple Registration Extension 将解决经过身份验证的用户的问题(您需要将 tz 转换为 numeric)。

                    另一种选择是根据用户代理的国家偏好推断时区。这是一种有点粗略的方法(不适用于 en-US),但可以很好地近似。

                    【讨论】:

                      【解决方案27】:

                      虽然建议将其包含在 HTTP 规范中,但到目前为止还没有报告客户端时区的 HTTP 标头。

                      如果是我,我可能会尝试使用客户端 JavaScript 获取时区,然后使用 Ajax 或其他方式将其提交到服务器。

                      【讨论】:

                      • 奇怪的是,这是该问题的唯一正确答案,它询问如何在服务器端进行操作。我怀疑有更多投票的其他答案的原因是因为一旦你意识到你需要在客户端这样做,你最终会使用其他答案。但是恕我直言,任何支持另一个答案的人也应该支持这个。
                      • 我相信最好的方法是使用 geo-ip 位置对可能的时区进行排序,并默认选择与用户代理时间偏移(需要 JavaScript)匹配(接近)的第一个。即使在此之后,您也必须提供一种方法来修复时区,即使这种方法会选择不正确的时区。
                      • @MikkoRantalainen 在使用代理时要小心,因为它们并不总是在标题中宣传自己。
                      • @Matthieu 现在有一个更好的答案:stackoverflow.com/a/11836123/334451
                      • 这是真正解决所提出问题的唯一答案。
                      猜你喜欢
                      • 1970-01-01
                      • 2014-04-09
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-11-22
                      • 2023-03-14
                      • 2023-04-04
                      • 2021-03-13
                      相关资源
                      最近更新 更多