Web/PHP

1970년 이전 날짜 사용가능한 date, mktime 조회수:429

aucd29 2013. 9. 26. 21:48
1970년 이전 날짜 사용가능한 date, mktime 조회수:429


1970년 이전 날짜에대해서는 date와 mktime 으로 값을 구할수가 없기에 찾아봤더니..1902년 부터인가를 구하는 프로그램이 있더군요..
그래서 그냥 1년 부터 구하도록 만들었습니다.
근데 문제는. 1년부터 1582년 10월 14일 까지는.. 가상의 날짜입니다.
현재 사용되는 달력은 1582년 10월 15일부터 고정되었다고 하더군요..

함수는. new_date와 new_mktime 이며 사용법은 같습니다.
그리고 아직 미완성이기 때문에.. 주로 사용되는 포맷만 구현되어있습니다 ^^;;
거기에 하나더 미완성인게.. new_mktime 의 인자값으로 음수가 들어갈경우는 처리가 되어있지 않습니다.. 지금 작업할게 있어서요 ㅋ
아래 내용을 복사해서 라이브러리에 넣어두고 사용하시면됩니다.
버그나 수정사항은 직접고치셨다면 여기에 올려주시면 감사하겠습니다. (__)
(902년 부터 뽑아주는 함수를 조금 참고했습니다.)

/*
  +---------------------------------------------------------------------+
  | Copyleft (L)  2005.1.9  by NiL                                      |
  +---------------------------------------------------------------------+
  | 본 프로그램은 제작자와는 전혀 무관하게 맘대로 복사, 수정, 파손      |
  | 또는, 대여, 판매할수 있습니다.                                      |
  | 수정된 소스는 제작자와 많은 사람들과 공유되기를 원합니다.           |
  +---------------------------------------------------------------------+
  | Author: Park J. NiL                                 |
  +---------------------------------------------------------------------+
*/

function is_leaf_year($y) {
    if(($y % 400) == 0) return true;
    else if(($y % 100) == 0) return false;
    else if(($y % 4) == 0) return true;
    else return false;
}

function new_mktime($hour, $min, $sec, $month, $day, $year) {
    $hour = intval($hour);
    $min = intval($min);
    $sec = intval($sec);
    $month = intval($month);
    $day = intval($day);
    $year = intval($year);

    $month_arr[0] = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
    $month_arr[1] = array(31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

    $_days = 0;
    $_secs = 0;

    $normal_year_days = 365;
    $leaf_year_days = 366;

    $_day_sec = 86400;
    $_hour_sec = 3600;
    $_min_sec = 60;

    $_day_min = 1440;
    $_hour_min = 60;

    $_day_hour = 24;

    $_timestamp = 0;

    // 초 더하기
    $secs = $sec;
    
    //  분을 초로
    $secs += $min * $_min_sec;

    //  시를 초로
    $secs += $hour * $_hour_sec;

    // 날 더하기
    $days = $day;
    
    // 월을 날짜로
    $_year_cnt = floor(($month - 1) / 12);
    $month = $month % 12;
    for($i = 0; $i < $month - 1; $i++)
    {
        $_month = ($i % 12) + 1;
        $leaf_flg = 0; // 기본값으로 윤달 아님

        if($_month == 2) // 2월이면 윤달 체크
        {
            if(is_leaf_year($year + $_year_cnt)) $leaf_flg = 1;
            else $leaf_flg = 0;
        }
        $days += $month_arr[$leaf_flg][$i];
    }

    // 년을 날짜로
    $year += $_year_cnt;
    for($i = 1; $i < $year; $i++)
    {
        $_year = $i;
        $days += is_leaf_year($_year) ? $leaf_year_days : $normal_year_days;
    }

    $_timestamp = ($days * $_day_sec) + $secs;
    return $_timestamp;
}

function get_days(&$t)
{
    $day_sec = 86400;
    $days = floor($t / $day_sec);
    $t = $t - (floor($t / $day_sec) * $day_sec);
    return $days;
}

function get_date($d)
{
    $leaf_year_days = 366;
    $normal_year_days = 365;
    
    $month_arr[0] = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
    $month_arr[1] = array(31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
    $year = 0;
    $month = 0;
    $day = 0;

    $flg = true;
    while($flg)
    {
        $year++;
        if(is_leaf_year($year))
        {
            if($d > $leaf_year_days) $d -= $leaf_year_days;
            else $flg = false;
            $leaf_flg = 1;
        }
        else
        {
            if($d > $normal_year_days) $d -= $normal_year_days;
            else $flg = false;
            $leaf_flg = 0;
        }
    }

    $month_cnt = 0;
    while($d > $month_arr[$leaf_flg][$month_cnt])
    {
        $d -= $month_arr[$leaf_flg][$month_cnt];
        $month_cnt++;
    }
    $month = $month_cnt + 1;
    $day = $d;
    return sprintf("%04d%02d%02d", $year, $month, $day);
}

function get_time($t)
{
    $hour_sec = 3600;
    $min_sec = 60;

    $hour = floor($t / $hour_sec);
    $min = floor(($t % $hour_sec) / $min_sec);
    $sec = $t % $min_sec;

    return sprintf("%02d%02d%02d", $hour, $min, $sec);
}

function cal_date($t)
{
    if($t == "")
    {
        return date("YmdHis");
    }
    else
    {
        $days = get_days(&$t);
        $date = get_date($days);
        $time = get_time($t);
        return $date.$time;
    }
}

function new_date()
{
    if(func_num_args() != 1 && func_num_args() != 2) return false;
    $format = func_get_arg(0);
    $timestamp = func_get_arg(1);
    $date = cal_date($timestamp);

    $year  = substr($date, 0, 4);
    $month = substr($date, 4, 2);
    $day   = substr($date, 6, 2);
    $hour  = substr($date, 8, 2);
    $min   = substr($date, 10, 2);
    $sec   = substr($date, 12, 2);

    $out_buf = "";
    for($i = 0; $i < strlen($format); $i++)
    {
        $c = substr($format, $i, 1);
        switch ($c)
        {
            case "a":
                $out_buf .= $hour < 12 ? "am" : "pm";
                break;
            case "A":
                $out_buf .= $hour < 12 ? "AM" : "PM";
                break;
            case "B":
                break;
            case "c":
                break;
            case "d":
                $out_buf .= sprintf("%02d", $day);
                break;
            case "D":
                break;
            case "F":
                break;
            case "g":
                $out_buf .= sprintf("%d", (($hour - 1) % 12) + 1);
                break;
            case "G":
                $out_buf .= sprintf("%d", $hour);
                break;
            case "h":
                $out_buf .= sprintf("%02d", (($hour - 1) % 12) + 1);
                break;
            case "H":
                $out_buf .= sprintf("%02d", $hour);
                break;
            case "i":
                $out_buf .= sprintf("%02d", $min);
                break;
            case "I":
                break;
            case "j":
                $out_buf .= sprintf("%d", $day);
                break;
            case "l":
                break;
            case "L":
                break;
            case "m":
                $out_buf .= sprintf("%02d", $month);
                break;
            case "M":
                break;
            case "n":
                $out_buf .= sprintf("%d", $month);
                break;
            case "O":
                break;
            case "r":
                break;
            case "s":
                $out_buf .= sprintf("%02d", $sec);
                break;
            case "S":
                break;
            case "t":
                break;
            case "T":
                break;
            case "U":
                break;
            case "w":
                break;
            case "W":
                break;
            case "Y":
                $out_buf .= sprintf("%04d", $year);
                break;
            case "y":
                $out_buf .= substr(sprintf("%04d", $year), 2, 2);
                break;
            case "z":
                break;
            case "Z":
                break;
            default :
                $out_buf .= $c;
        }
    }
    return $out_buf;
}
?>

NiL 사용법 예제입니다.
[jnils@hosting1 typhoon]$ cat ./test.php
#!/usr/local/bin/php
include "lib.php";
echo date("YmdHis", mktime(71, 71, 71, 15, 445, 1999))."\n";
echo new_date("YmdHis", new_mktime(71, 71, 71, 15, 445, 1999))."\n";
?>
[jnils@hosting1 typhoon]$ ./test.php
20010522001211
20010522001211
01/09 17:06:18 코멘트 지우기
1년? 근데 이 달력은 어디에 쓰는거죠?
성경에 나오는 사건들의 요일을 알수 있으려나? ^^
01/09 17:28:43 코멘트 지우기
NiL ㅋㅋ 1950년 날짜가 필요해서 만든겁니당 01/09 18:13:57 코멘트 지우기
지나다 $timestamp = func_get_arg(1); 이게
$timestamp = func_get_arg(); 이렇게 되어야 하지 않나요?
01/09 20:32:35 코멘트 지우기
NiL func_get_arg(int) 이건 하나씩 받기구요
func_get_args() 이건 배열로 받기입니당 ^^;;
01/10 0:06:36 코멘트 지우기
산이 안녕하세요?
아주 먼 과거나 미래에 대한 시간 또는 시각을 다룰려면
`율리우스 적일(Julian day)' 을 사용해야 합니다.

PHP 에서는 Calendar 함수가 있으므로 이것을 사용하면
됩니다.

율리우스 적일은 (역학에서 참조)
`BC 4713년 1월 1일 12시(UT) 이후 경과한 평균태양일(365)'
으로 정의되고, `JD' 라고도 표시합니다.

예)
2005.01.10 00:06:00 => J2005.00069 => 2453381.25 JD

참고로
KST 는 한국표준시, UT는 세계시, TT 는 지구시, 지구역학시
는 TDT 라고 합니다(KST = UT + 9H).

예1)
먼 과거 1000년 전(시간) 오늘의 요일 알아보기:

$JD = gregoriantojd(1,10,1005); // 2086312
echo jdtojulian($JD); // 1/5/1000 (5일의 차이가 있군요)
echo jddayofweek($JD,1); // Friday (금요일이군요)

예2)
먼 과거 1000년 1월 10일(시각) 요일 알아보기:

$JD += 5; // 2086317
echo jdtojulian($JD); // 1/10/1000
echo jddayofweek($JD,1); // Wednesday (수요일이군요)
01/10 1:09:04 코멘트 지우기
흑심품은연필 C언어로 만들면 더 좋겠어용 ^^ php 계발자는 알고 있겠죠 패치않했나요?? 궁금하네요 01/10 12:53:53 코멘트 지우기
NiL 산이//
아주 먼 옛날이나 아주 먼 미래가 아니라.. 단지 컴퓨터에서 사용하는 날짜 한계때문에 불편해서 만들어본것입니다 ^-^;;
아래는 제가 참고한 내용입니다.
http://www.wonil-c.co.kr/data/story.htm <- 참고사이트
부활절을 맞추려고 10일 빼먹어 다시 춘분날의 위치를 부활절 제정 당시의 날짜인 3월 21일로 되돌려 놓기 위해 1582년10월 4일 (목요일)의 다음날을 1582년 10월 15일 (금요일)로 변경했다. 따라서 1583년부터는 춘분날이 3월 21일로 밀려나게 됐다. 하지만 1582년 10월 5일부터 14일까지의 날짜는 존재하지 않는 날이 됐다. 이 때 날짜는 건너뛰었지만 요일은 그대로 이어졌다. 이를 그레고리력이라 하는데, 오늘날 우리가 사용하는 양력이 이 것이다.
여기서 마지막으로 고정된 달력이 그레고리력이라는데..이걸 기준으로 앞쪽은 날짜를 만들어버리도록했습니다.
01/10 15:34:20 코멘트 지우기
NiL 흑심품은연필//
흐흐 저도 C로 하고 싶지만... php로 얼싸쿠나하고 만든이유가..-_-;; int (32bit) 의 범위를 훨씬 넘어가는 큰수도 그냥 연산이 되기때문에 한거구요 C로 한다면 아마 더 귀찮은 작업이 필요할듯 합니다 ㅋㅋ