IX. Calendar 日历函数

简介

日历扩展是由一系列简单的日历格式转换函数组成。媒介或标准是基于儒略日计数(Julian Day Count)。儒略日计数是从公元前 4713 年 1 月 1 日开始计算的。在不同的日历系统中转换,必须先将其转换为儒略日计数,然后转换为目标日历格式。儒略日计数与罗马儒略历(Julian Calendar)完全不同!更多关于儒略日计数的信息,请访问 http://www.hermetic.ch/cal_stud/jdn.htm。更多关于日历系统的信息,请访问 http://www.boogle.com/info/cal-overview.html。从此页面引用的信息包含了这些介绍,在引号之内。

安装

要使用本类函数,需要在编译 PHP 时加上 --enable-calendar

PHP 的 Windows 版本已经内置该扩展模块的支持。无需加载任何附加扩展库即可使用这些函数。

运行时配置

本扩展模块在 php.ini 中未定义任何配置选项。

资源类型

本扩展模块未定义任何资源类型。

预定义常量

以下常量由本扩展模块定义,因此只有在本扩展模块被编译到 PHP 中,或者在运行时被动态加载后才有效。

CAL_GREGORIAN (integer)

CAL_JULIAN (integer)

CAL_JEWISH (integer)

CAL_FRENCH (integer)

CAL_NUM_CALS (integer)

CAL_DOW_DAYNO (integer)

CAL_DOW_SHORT (integer)

CAL_DOW_LONG (integer)

CAL_MONTH_GREGORIAN_SHORT (integer)

CAL_MONTH_GREGORIAN_LONG (integer)

CAL_MONTH_JULIAN_SHORT (integer)

CAL_MONTH_JULIAN_LONG (integer)

CAL_MONTH_JEWISH (integer)

CAL_MONTH_FRENCH (integer)

以下常量自 PHP 4.3.0 起可用:

CAL_EASTER_DEFAULT (integer)

CAL_EASTER_ROMAN (integer)

CAL_EASTER_ALWAYS_GREGORIAN (integer)

CAL_EASTER_ALWAYS_JULIAN (integer)

以下常量自 PHP 5.0.0 起可用:

CAL_JEWISH_ADD_ALAFIM_GERESH (integer)

CAL_JEWISH_ADD_ALAFIM (integer)

CAL_JEWISH_ADD_GERESHAYIM (integer)

目录
cal_days_in_month -- Return the number of days in a month for a given year and calendar
cal_from_jd -- Converts from Julian Day Count to a supported calendar
cal_info -- Returns information about a particular calendar
cal_to_jd -- Converts from a supported calendar to Julian Day Count
easter_date --  Get Unix timestamp for midnight on Easter of a given year
easter_days --  Get number of days after March 21 on which Easter falls for a given year
FrenchToJD --  Converts a date from the French Republican Calendar to a Julian Day Count
GregorianToJD --  Converts a Gregorian date to Julian Day Count
JDDayOfWeek -- Returns the day of the week
JDMonthName -- Returns a month name
JDToFrench --  Converts a Julian Day Count to the French Republican Calendar
JDToGregorian -- Converts Julian Day Count to Gregorian date
jdtojewish --  Converts a Julian day count to a Jewish calendar date
JDToJulian --  Converts a Julian Day Count to a Julian Calendar Date
jdtounix -- Convert Julian Day to Unix timestamp
JewishToJD --  Converts a date in the Jewish Calendar to Julian Day Count
JulianToJD --  Converts a Julian Calendar date to Julian Day Count
unixtojd -- Convert Unix timestamp to Julian Day

add a note add a note User Contributed Notes
fRay Ferguson
21-Apr-2006 10:32
The following is a light reimplimentation of some of these functions wich can be used in an include file to work around the lack of --with-calendar in php implimentations.

<?php

/* IMPLEMENTS SUBSET OF PHP CALENDAR FUNCTIONS ON SYSTEMS COMPILED W/O --enable-calendar */

if (!function_exists('cal_days_in_month')){
       function
cal_days_in_month($a_null, $a_month, $a_year) {
               return
date('t', mktime(0, 0, 0, $a_month+1, 0, $a_year));
       }
}

if (!
function_exists('cal_to_jd')){
       function
cal_to_jd($a_null, $a_month, $a_day, $a_year){
               if (
$a_month <= 2 ){
                    
$a_month = $a_month + 12 ;
                    
$a_year = $a_year - 1 ;
               }
              
$A = intval($a_year/100);
              
$B = intval($A/4) ;
              
$C = 2-$A+$B ;
              
$E = intval(365.25*($a_year+4716)) ;
              
$F = intval(30.6001*($a_month+1));
               return
intval($C+$a_day+$E+$F-1524) ;
       }
}

if (!
function_exists('get_jd_dmy')) {
   function
get_jd_dmy($a_jd){
    
$W = intval(($a_jd - 1867216.25)/36524.25) ;
    
$X = intval($W/4) ;
    
$A = $a_jd+1+$W-$X ;
    
$B = $A+1524 ;
    
$C = intval(($B-122.1)/365.25) ;
    
$D = intval(365.25*$C) ;
    
$E = intval(($B-$D)/30.6001) ;
    
$F = intval(30.6001*$E) ;
    
$a_day = $B-$D-$F ;
     if (
$E > 13 ) {
      
$a_month=$E-13 ;
      
$a_year = $C-4715 ;
     } else {
      
$a_month=$E-1 ;
      
$a_year=$C-4716 ;
     }
     return array(
$a_month, $a_day, $a_year) ;
   }
}

if (!
function_exists('jdmonthname')) {
       function
jdmonthname($a_jd,$a_mode){
              
$tmp = get_jd_dmy($a_jd) ;
              
$a_time = "$tmp[0]/$tmp[1]/$tmp[2]" ;
               switch(
$a_mode) {
                       case
0:
                               return
strftime("%b",strtotime("$a_time")) ;
                       case
1:
                               return
strftime("%B",strtotime("$a_time")) ;
               }
       }
}

if (!
function_exists('jddayofweek')) {
       function
jddayofweek($a_jd,$a_mode){
              
$tmp = get_jd_dmy($a_jd) ;
              
$a_time = "$tmp[0]/$tmp[1]/$tmp[2]" ;
               switch(
$a_mode) {
                       case
1:
                               return
strftime("%A",strtotime("$a_time")) ;
                       case
2:
                               return
strftime("%a",strtotime("$a_time")) ;
                       default:
                               return
strftime("%w",strtotime("$a_time")) ;
               }
       }
}

?>
amichauer at gmx dot de
28-Jun-2005 12:46
<?php

class HijriCalendar
{
   function
monthName($i) // $i = 1..12
  
{
       static
$month  = array(
          
"Mxrrm", "Safar", "Rabig-l-wwl", "Rabig-l-Axr",
          
"Cmd-l-wwl", "Cmd-l-Axr", "Racb", "bn",
          
"Ramazan", "wl", "Z-l-Qd", "Z-l-Xicc"
      
);
       return
$month[$i-1];
   }

   function
GregorianToHijri($time = null)
   {
       if (
$time === null) $time = time();
      
$m = date('m', $time);
      
$d = date('d', $time);
      
$y = date('Y', $time);

       return
HijriCalendar::JDToHijri(
          
cal_to_jd(CAL_GREGORIAN, $m, $d, $y));
   }

   function
HijriToGregorian($m, $d, $y)
   {
       return
jd_to_cal(CAL_GREGORIAN,
          
HijriCalendar::HijriToJD($m, $d, $y));
   }

  
# Julian Day Count To Hijri
  
function JDToHijri($jd)
   {
      
$jd = $jd - 1948440 + 10632;
      
$n  = (int)(($jd - 1) / 10631);
      
$jd = $jd - 10631 * $n + 354;
      
$j  = ((int)((10985 - $jd) / 5316)) *
           ((int)(
50 * $jd / 17719)) +
           ((int)(
$jd / 5670)) *
           ((int)(
43 * $jd / 15238));
      
$jd = $jd - ((int)((30 - $j) / 15)) *
           ((int)((
17719 * $j) / 50)) -
           ((int)(
$j / 16)) *
           ((int)((
15238 * $j) / 43)) + 29;
      
$m  = (int)(24 * $jd / 709);
      
$d  = $jd - (int)(709 * $m / 24);
      
$y  = 30*$n + $j - 30;

       return array(
$m, $d, $y);
   }

  
# Hijri To Julian Day Count
  
function HijriToJD($m, $d, $y)
   {
       return (int)((
11 * $y + 3) / 30) +
          
354 * $y + 30 * $m -
           (int)((
$m - 1) / 2) + $d + 1948440 - 385;
   }
};

$hijri = HijriCalendar::GregorianToHijri( time() );
echo
$hijri[1].'. '.HijriCalendar::monthName($hijri[0]).' '.$hijri[2];

?>
pouya
04-Apr-2004 02:39
There is an implementation of the Persian calendar at www.farsiweb.info.
jthome at fcgov dot com
03-Oct-2003 02:38
Had a similar problem as curlee, except I needed to create a JDE_ERP date.  [format is CYYDDD]

<?php

function jde_date_create($month, $day, $year){
  
/*
   *  NOTE: $month and $day CANNOT have leading zeroes,
   *        $year must be'YYYY' format
   */
  
$jde_year_prefix = substr($year, 0, 1) - 1;
  
$jde_year_suffix = substr($year, -2);
  
  
//note that valid years for mktime are 1902-2037
  
$timestamp = mktime(0,0,0,$month, $day, $year);
  
$baseline_timestamp = mktime(0,0,0,1,0,$year);
  
  
$day_count = round(($timestamp - $baseline_timestamp)/86400);
  
$day_count_padded = str_pad($day_count,3,"0",STR_PAD_LEFT);

   return (
$jde_year_prefix . $jde_year_suffix . $day_count_padded);
  
}

echo
jde_date_create(6,25,2000);// will return '103176'

?>

--
Jim
curlee at mindspring dot com
29-Aug-2003 11:55
I solved a problem with Julian dates that are used in the JD Edwards ERP package (running on AS/400).  The Julian format for this system is as follows:  CYYDDD

Where C is 0 for 1900 and 1 for 2000
DDD is the day of the year count

I used the mktime built-in php function to convert dates to the normal DD/MM/YYYY format.  This function will convert dates that are between 1970 and 2038 (limitation of unix timestamps and the mktime function)

The $jde_date var needs to be a 6 len STRING.... if you use a numeric var type it will drop the leading 0 for any date that represents 1900.... this will botch the substr functions and thus make the whole thing wrong. 

function jde_date_conv($jde_date)
{

$ct = substr($jde_date,0,1);
$yr = substr($jde_date,1,2);
$dy = substr($jde_date,3,3);

if($ct == 0) $yr_pfx = 19;
if($ct == 1) $yr_pfx = 20;

$tlt_yr = $yr_pfx.$yr;

$base_time = mktime(0,0,0,1,0,$tlt_yr);

$unix_time = ($dy * 86400) + $base_time;

return date("m/d/Y" , $unix_time);
}
carlj at vibez dot ca
17-Jun-2003 03:28
Why not do something like this, to find the number of days in a month?

$monthNum = date("n"); // or any value from 1-12
$year        = date("Y"); // or any value >= 1
$numDays  = date("t",mktime(0,0,0,$monthNum,1,$year))

This will tell you if there is 28-31 days in a month
dy64 at dy64 dot de
12-Nov-2002 10:18
Best performance:
/*
 * Find the number of days in a month
 * Year is between 1 and 32767 inclusive
 * Month is between 1 and 12 inclusive
 */
function DayInMonth($month, $year) {
   var $daysInMonth = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
   if ($month != 2) return $daysInMonth[$month - 1];
   return (checkdate($month, 29, $year)) ? 29 : 28;
}
kmcm at bigfoot dot com
21-Jan-2002 10:42
if, like me, you don't have a PHP build that includes the cal functions, you may want to use this function for sorting out leap year.

function days_in_feb($year){

   //$year must be YYYY
   //[gregorian] leap year math :
  
   if ($year < 0) $year++;
   $year += 4800;

   if ( ($year % 4) == 0) {
       if (($year % 100) == 0) {
           if (($year % 400) == 0) {
               return(29);
           } else {
               return(28);
           }
       } else {
           return(29);
       }
   } else {
       return(28);
   }
}

of course the next leap year isn't until the end of the century but this makes for timeless code I guess ...or if you are using 2000 in your dates or are going far back in time, etc, it is necessary.
mikebabcock at pobox dot com
18-Jul-2000 12:20
There are two world calculations for the date of Easter.  The Easter date function should account for this; one used (generally) by the Western world and one (generally) used by the Eastern (the official date used by the East Orthodox Church).
ssharma at odc dot net
31-Jan-2000 07:36
If you're interested in dates/calendars, check out the MCAL stuff.
http://www.php.net/manual/ref.mcal.php3