Programing

사용자의 시간대 결정

crosscheck 2020. 10. 3. 09:59
반응형

사용자의 시간대 결정


웹 서버가 웹 페이지 내에서 사용자의 시간대를 결정할 수있는 표준 방법이 있습니까?

아마도 HTTP 헤더 또는 user-agent문자열의 일부에서 왔습니까?


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

이 메서드 getTimezoneOffset()는 GMT에서 시간을 빼고 분 수를 반환합니다. 따라서 GMT-8에 거주하는 경우 480을 반환합니다.

이것을 시간으로 나누려면 60으로 나눕니다. 또한 기호가 필요한 것과 반대라는 점에 유의하십시오. GMT에서 시간대의 오프셋이 아니라 시간대에서 GMT의 오프셋을 계산하는 것입니다. 이 문제를 해결하려면 -1을 곱하면됩니다.

또한 w3school 은 다음과 같이 말합니다.

일광 절약 시간제를 사용하기 때문에 반환 된 값은 상수가 아닙니다.


내가 본 시간대를 결정하는 가장 인기있는 (== standard?) 방법은 단순히 사용자에게 물어 보는 것입니다. 웹 사이트에 가입이 필요한 경우 사용자의 프로필 데이터에 저장할 수 있습니다. anon 사용자의 경우 날짜는 UTC 또는 GMT 등으로 표시 될 수 있습니다.

나는 현명한 알렉이 되려는 것이 아닙니다. 때로는 일부 문제에 프로그래밍 컨텍스트 외부에서 더 나은 솔루션이있을 수 있습니다.


HTTP 사양에 포함하도록 제안되었지만 지금까지 클라이언트 시간대를보고 할 HTTP 헤더는 없습니다.

저라면 아마도 클라이언트 측 JavaScript를 사용하여 시간대를 가져온 다음 Ajax 등을 사용하여 서버에 제출하려고 할 것입니다.


JavaScript는 클라이언트의 현지 시간을 얻는 가장 쉬운 방법입니다. XMLHttpRequest사용 하여 현지 시간을 되 돌리는 것이 좋습니다. 실패하면 IP 주소를 기반으로 감지 된 시간대로 돌아갑니다.

지리적 위치에 관해서 는 여러 프로젝트에서 MaxMind GeoIP사용 했으며 시간대 데이터를 제공하는지 확실하지 않지만 잘 작동합니다. 비용을 지불하는 서비스이며 데이터베이스에 월별 업데이트를 제공합니다. 여러 웹 언어로 래퍼를 제공합니다.


다음은 브라우저가있는 시간대를 결정하는 강력한 JavaScript 솔루션입니다.

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

https://bitbucket.org/pellepim/jstimezonedetect


여기에 더 완전한 방법이 있습니다.

  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;
}

JS에서 TZ 및 DST 가져 오기 (Way Back Machine을 통해)


먼저, JavaScript의 시간대 감지가 불완전하다는 것을 이해하십시오. 객체 의 인스턴스를 사용하여 특정 날짜 및 시간에 대한 현지 시간대 오프셋가져올 수 있지만 .NET 과 같은 전체 IANA 시간대는 완전히 다릅니다 .getTimezoneOffsetDateAmerica/Los_Angeles

그래도 작동 할 수있는 몇 가지 옵션이 있습니다.

  • 대부분의 최신 브라우저는 ECMAScript 국제화 API 구현에서 IANA 시간대를 지원 하므로 다음과 같이 할 수 있습니다.

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

    결과는 코드가 실행중인 컴퓨터의 IANA 시간대 설정이 포함 된 문자열입니다.

    지원되는 환경은 Intl 호환성 표에 나열 되어 있습니다. DateTimeFormat섹션을 확장하고 라는 기능을 확인 resolvedOptions().timeZone defaults to the host environment합니다.

    • Luxon 과 같은 일부 라이브러리 는이 API를 사용하여 luxon.Settings.defaultZoneName.
  • 이전 웹 브라우저와 같은 더 광범위한 환경을 지원해야하는 경우 라이브러리를 사용 하여 표준 시간대에 대한 정보 를 바탕으로 추측 할 수 있습니다 . IntlAPI가 사용 가능한 경우 먼저 API를 시도하고 사용할 수없는 경우 에는 결과를 사용하여 내부 데이터 세트에서 적절한 시간대를 선택하여 여러 시점에 대해 객체 getTimezoneOffset기능을 조사합니다 Date.

    jsTimezoneDetect순간 시간대는 이 기능을 가지고있다.

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

    두 경우 모두 결과는 추측으로 만 생각할 수 있습니다. 대부분의 경우 추측이 정확할 수 있지만 전부는 아닙니다.

    또한 이러한 라이브러리는 많은 이전 JavaScript 구현이 현지 시간대에 대한 현재 일광 절약 시간 규칙 만 인식하고 있다는 사실에 대응하기 위해 주기적으로 업데이트해야 합니다. 자세한 내용은 여기에서 확인하세요.

궁극적으로 더 나은 접근 방식은 실제로 사용자에게 시간대를 묻는 것입니다. 변경할 수있는 설정을 제공하십시오. 위 옵션 중 하나를 사용하여 기본 설정 을 선택할 수 있지만 앱에서 이탈하는 것을 불가능하게 만들지 마십시오.

또한 사용자 컴퓨터의 시간대 설정에 전혀 의존 하지 않는 완전히 다른 접근 방식도 있습니다 . 대신 위도 및 경도 좌표를 수집 할 수있는 경우 다음 방법 중 하나를 사용하여 해당 좌표를 시간대로 확인할 수 있습니다 . 이것은 모바일 장치에서 잘 작동합니다.


Unkwntech의 접근 방식을 사용하여 jQuery와 PHP를 사용하여 함수를 작성했습니다. 이것은 테스트되고 작동합니다!

시간대를 변수로 지정하려는 PHP 페이지에서 페이지 상단 근처에 다음 코드 스 니펫이 있습니다.

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

이제 만들려고하는 세션 변수 "time"을 읽습니다.

같은 페이지의 <head>에 먼저 jQuery를 포함해야합니다.

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>

또한 <head>의 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) 또는 사용자가 속한 시간대를 반환합니다.


jQuery를 사용 하여 AJAX 요청에서 시간대 오프셋을 HTTP 헤더로 제출하려면

$.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(); 에서 사용하여 실제 시간대 이름을 가져 오는 것과 유사한 작업을 수행 할 수도 있습니다 .


나는 여전히 시간대를 얻는 자세한 답변을 보지 못했습니다. IP 주소로 지오 코딩하거나 PHP (웃음)를 사용하거나 오프셋에서 잘못 추측 할 필요가 없습니다.

첫째, 시간대는 GMT의 오프셋이 아닙니다. 시간 규칙이 현지 표준에 의해 설정된 토지입니다. 일부 국가에서는 일광 절약 시간제를 사용하며 다른 시간에 DST를 켭니다. 현재 오프셋뿐만 아니라 실제 영역을 얻는 것이 일반적으로 중요합니다.

예를 들어 사용자 기본 설정에서이 시간대를 저장하려는 경우 오프셋뿐만 아니라 영역을 원합니다. 실시간 변환의 경우 그다지 중요하지 않습니다.

이제 자바 스크립트로 시간대를 얻으려면 다음을 사용할 수 있습니다.

>> 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


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();
?>

But as per my point of view, it’s better to ask to the users if registration is mandatory in your project.


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;
}

Simply provide your times in Unix timestamp format to this function; JavaScript already knows the timezone of the user.

Like this:

PHP:

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

This will always show the times correctly based on the timezone the person has set on his/her computer clock. There is no need to ask anything to anyone and save it into places, thank god!


Don't use the IP address to definitively determine location (and hence timezone)-- that's because with NAT, proxies (increasingly popular), and VPNs, IP addresses do not necessarily realistically reflect the user's actual location, but the location at which the servers implementing those protocols reside.

Similar to how US area codes are no longer useful for locating a telephone user, given the popularity of number portability.

IP address and other techniques shown above are useful for suggesting a default that the user can adjust/correct.


Easy, just use the JavaScript getTimezoneOffset function like so:

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

The magic all seems to be in

visitortime.getTimezoneOffset()

That's cool, I didn't know about that. Does it work in Internet Explorer, etc? From there you should be able to use JavaScript to Ajax, set cookies, whatever. I'd probably go the cookie route myself.

You'll need to allow the user to change it though. We tried to use geolocation (via maxmind) to do this a while ago, and it was wrong reasonably often - enough to make it not worth doing, so we just let the user set it in their profile, and show a notice to users who haven't set theirs yet.


If you happen to be using OpenID for authentication, Simple Registration Extension would solve the problem for authenticated users (You'll need to convert from tz to numeric).

Another option would be to infer the time zone from the user agent's country preference. This is a somewhat crude method (won't work for en-US), but makes a good approximation.


Here is an article (with source code) that explains how to determine and use localized time in an ASP.NET (VB.NET, C#) application:

It's About Time

In short, the described approach relies on the JavaScript getTimezoneOffset function, which returns the value that is saved in the session cookie and used by code-behind to adjust time values between GMT and local time. The nice thing is that the user does not need to specify the time zone (the code does it automatically). There is more involved (this is why I link to the article), but provided code makes it really easy to use. I suspect that you can convert the logic to PHP and other languages (as long as you understand ASP.NET).


It is simple with JavaScript and PHP:

Even though the user can mess with his/her internal clock and/or timezone, the best way I found so far, to get the offset, remains new Date().getTimezoneOffset();. It's non-invasive, doesn't give head-aches and eliminates the need to rely on third parties.

Say I have a table, users, that contains a field date_created int(13), for storing Unix timestamps;

Assuming a client creates a new account, data is received by post, and I need to insert/update the date_created column with the client's Unix timestamp, not the server's.

Since the timezoneOffset is needed at the time of insert/update, it is passed as an extra $_POST element when the client submits the form, thus eliminating the need to store it in sessions and/or cookies, and no additional server hits either.

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;

Say the server receives tzo as $_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);

Insert/update date_created=$user_timestamp.

When retrieving the date_created, you can convert the timestamp like so:

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

Now, this example may fit one's needs, when it comes to inserting a first timestamp... When it comes to an additional timestamp, or table, you may want to consider inserting the tzo value into the users table for future reference, or setting it as session or as a cookie.

P.S. BUT what if the user travels and switches timezones. Logs in at GMT+4, travels fast to GMT-1 and logs in again. Last login would be in the future.

I think... we think too much.


You could do it on the client with moment-timezone and send the value to server; sample usage:

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

Getting a valid TZ Database timezone name in PHP is a two-step process:

  1. With JavaScript, get timezone offset in minutes through getTimezoneOffset. This offset will be positive if the local timezone is behind UTC and negative if it is ahead. So you must add an opposite sign to the offset.

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

    Pass this offset to PHP.

  2. In PHP convert this offset into a valid timezone name with timezone_name_from_abbr function.

    // 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>
    

I've written a blog post on it: How to Detect User Timezone in PHP. It also contains a demo.


A simple way to do it is by using:

new Date().getTimezoneOffset();

One possible option is to use the Date header field, which is defined in RFC 7231 and is supposed to include the timezone. Of course, it is not guaranteed that the value is really the client's timezone, but it can be a convenient starting point.


Here's how I do it. This will set the PHP default timezone to the user's local timezone. Just paste the following on the top of all your pages:

<?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
?>

Try this PHP code:

<?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'];
?>

참고URL : https://stackoverflow.com/questions/13/determine-a-users-timezone

반응형