본문 바로가기

Story/php

php date_format smarty smarty_modifier_date_format is_numeric 64bit 날짜 문제

반응형

php smarty 를 32비트 운영체계에서 사용하다가 64비트로 os를 업그래이드 한후

"20130812174109" 값을 {#$BoardConts.reg_dm|date_format:"%Y.%m.%d"#} 이런식으로 출력했을때 3000년이 넘게 나오는등 이상이 생겼다.

구글링을 통해서 찾아보니

http://www.smarty.net/forums/viewtopic.php?p=8837 에서

 

By debugging smarty_make_timestamp() function, it turns out that strtotime() of this value is returning something that is_numeric() so it is returned. That means the special mysql timestamp case is not handled as it comes after the return.

I suggest the function sould be modified as below. It seems to work for me, but I let you appreciate if it is relevant:

와 같은 설명과 아래와 같은 해결책(CODE)를 찾을 수 있었다.

 

/* 원래 코드
function smarty_make_timestamp($string)
{
    if(empty($string)) {
        $string = "now";
    }
    $time = strtotime($string);
    if (is_numeric($time) && $time != -1)
        return $time;

    // is mysql timestamp format of YYYYMMDDHHMMSS?
    if (preg_match('/^\d{14}$/', $string)) {
        $time = mktime(substr($string,8,2),substr($string,10,2),substr($string,12,2),
               substr($string,4,2),substr($string,6,2),substr($string,0,4));

        return $time;
    }

    // couldn't recognize it, try to return a time
    $time = (int) $string;
    if ($time > 0)
        return $time;
    else
        return time();
}
*/

 

// 변경된 코드
function smarty_make_timestamp($string)
{
    if(empty($string)) {
        $string = "now";
    }

    // is mysql timestamp format of YYYYMMDDHHMMSS?
    if (preg_match('/^\d{14}$/', $string)) {
        $time = mktime(substr($string,8,2),substr($string,10,2),substr($string,12,2),
               substr($string,4,2),substr($string,6,2),substr($string,0,4));

        return $time;
    }

    $time = strtotime($string);
    if (is_numeric($time) && $time != -1)
        return $time;

    // couldn't recognize it, try to return a time
    $time = (int) $string;
    if ($time > 0)
        return $time;
    else
        return time();
}

결국 숫자에 대한 문제인대

https://news.ycombinator.com/item?id=3900997 에서 보니 32 비트에서 64 비트로 바뀌면서

(I assume that "what." is a request for an explanation.)

A float can store an exact integer of up to 53 bits even on a 32 bit machine.

PHP only has signed ints. If you need to store an unsigned int you can either store it internally as signed and only convert it to unsigned with printf() when you output it (and deal with the complexity of comparisons), or use a float and limit yourself to 53 bits.

If you have a 64 bit machine then of course you can easily fit an unsigned 32 bit int in that range. But it's wise not to rely on that at least for another few years.

In short, if you need more than 32 signed bits of range, and you want to make sure your code will run on any machine, then use a float. If you know you only use 64 bit machines then you have more flexibility. (You can use PHP_INT_SIZE and PHP_INT_MAX to check.)

If you need even more range than that then use the built in GMP library.

Also, PHP will automatically convert numbers that are too large from ints to float, so normally you don't see any of this. It's only if you use settype() to force an int that you have to pay attention to this.

정수에 대한 비트 범위가 바뀐것이 문제인거 같다

반응형