PHP Conference Japan 2024

easter_date

(PHP 4, PHP 5, PHP 7, PHP 8)

easter_date取得指定年份復活節當天午夜的 Unix 時間戳記

描述

easter_date(?int $year = null, int $mode = CAL_EASTER_DEFAULT): int

傳回指定年份復活節當天午夜對應的 Unix 時間戳記。

復活節的日期由公元 325 年的尼西亞公會議定義為春分當天或之後第一個滿月之後的星期日。 假設春分總是落在 3 月 21 日,因此計算簡化為確定滿月的日期和下一個星期日的日期。 此處使用的演算法是在公元 532 年左右由狄奧尼修斯·伊希古斯引入的。 在儒略曆下(1753 年之前),使用一個簡單的 19 年週期來追蹤月球的相位。 在格里曆下(1753 年之後 - 由克拉維烏斯和利利烏斯設計,並於 1582 年 10 月由教宗格列高利十三世引入,並於 1752 年 9 月引入英國及其當時的殖民地),會加入兩個修正因子,以使週期更準確。

參數

year

對於 32 位元系統,年份必須是介於 1970 年和 2037 年之間的數字,對於 64 位元系統,則介於 1970 年和 2,000,000,000 年之間。如果省略或為 null,則預設為當地時間的當前年份。

mode

設定為 CAL_EASTER_ALWAYS_JULIAN 時,允許根據儒略曆計算復活節日期。另請參閱日曆常數

傳回值

復活節日期為 Unix 時間戳記。

錯誤/例外

如果在 32 位元系統上執行時,年份早於 1970 年或晚於 2037 年,或在 64 位元系統上晚於 2,000,000,000 年,則會擲回 ValueError

變更紀錄

版本 描述
8.3.0 在 64 位元系統上,year 參數現在接受介於 1970 到 2,000,000,000 之間的值。
8.0.0 year 現在可為 null。
8.0.0 year 超出允許範圍時,現在會擲回 ValueError。先前,會產生 E_WARNING,且函式會傳回 false

範例

範例 #1 easter_date() 範例

<?php

echo date("M-d-Y", easter_date(1999)); // Apr-04-1999
echo date("M-d-Y", easter_date(2000)); // Apr-23-2000
echo date("M-d-Y", easter_date(2001)); // Apr-15-2001

?>

範例 #2 將 easter_date()DateTime 搭配使用

<?php

$timestamp
= easter_date(2023);

$datetime = new \DateTime();
$datetime->setTimestamp($timestamp);

echo
$datetime->format('M-d-Y'); // Apr-09-2023

?>

註解

注意:

easter_date() 依賴您系統的 C 程式庫時間函式,而不是使用 PHP 的內部日期和時間函式。因此,easter_date() 使用 TZ 環境變數來確定其應運作的時區,而不是使用 PHP 的預設時區,這可能會導致當此函式與 PHP 中的其他日期函式一起使用時產生非預期的行為。

作為一種變通方法,您可以使用 easter_days()DateTimeDateInterval 來計算您 PHP 時區中復活節的開始時間,如下所示

<?php
function get_easter_datetime($year) {
$base = new DateTime("$year-03-21");
$days = easter_days($year);

return
$base->add(new DateInterval("P{$days}D"));
}

foreach (
range(2012, 2015) as $year) {
printf("Easter in %d is on %s\n",
$year,
get_easter_datetime($year)->format('F j'));
}
?>

上面的範例將輸出

Easter in 2012 is on April 8
Easter in 2013 is on March 31
Easter in 2014 is on April 20
Easter in 2015 is on April 5

參見

  • easter_days() - 取得指定年份復活節落在 3 月 21 日之後的天數,用於計算 1970 年之前或 2037 年之後的復活節

新增註解

使用者貢獻的註解 7 條註解

30
maxie
16 年前
為了計算東正教教會正確的復活節日期,我根據 Meeus Julian 演算法建立了一個函式

<?php
function orthodox_eastern($year) {
$a = $year % 4;
$b = $year % 7;
$c = $year % 19;
$d = (19 * $c + 15) % 30;
$e = (2 * $a + 4 * $b - $d + 34) % 7;
$month = floor(($d + $e + 114) / 31);
$day = (($d + $e + 114) % 31) + 1;

$de = mktime(0, 0, 0, $month, $day + 13, $year);

return
$de;
}
?>
9
Alexander Bliznyuk
7 年前
感謝 @Maxie 提供的計算東正教復活節日期的演算法。
不過可以改進一下。你為了將儒略曆對應到格里曆而加上了 13 天。但 13 天並不是一個常數。它是格里曆中修正的累積誤差,應該使用這個公式計算:(int)($year / 100) - (int)($year / 400) - 2
11
py dot lebecq at gmail dot com
14 年前
我最近必須寫一個函數,讓我能夠知道今天是否為假日。

在法國,我們有一些假日是根據復活節日期而定。也許這對某些人會有幫助。

只要在 $holidays 陣列中修改你所在國家的實際假日日期即可。

<?php
/**
* 這個函數會傳回一個對應到法國假期的時間戳記陣列
*/
protected static function getHolidays($year = null)
{
if (
$year === null)
{
$year = intval(date('Y'));
}

$easterDate = easter_date($year);
$easterDay = date('j', $easterDate);
$easterMonth = date('n', $easterDate);
$easterYear = date('Y', $easterDate);

$holidays = array(
// 這些日期是固定的
mktime(0, 0, 0, 1, 1, $year), // 1月1日
mktime(0, 0, 0, 5, 1, $year), // 勞動節
mktime(0, 0, 0, 5, 8, $year), // 同盟國勝利日
mktime(0, 0, 0, 7, 14, $year), // 法國國慶日
mktime(0, 0, 0, 8, 15, $year), // 聖母升天日
mktime(0, 0, 0, 11, 1, $year), // 諸聖節
mktime(0, 0, 0, 11, 11, $year), // 休戰日
mktime(0, 0, 0, 12, 25, $year), // 聖誕節

// 這些日期的日期取決於復活節
mktime(0, 0, 0, $easterMonth, $easterDay + 2, $easterYear),
mktime(0, 0, 0, $easterMonth, $easterDay + 40, $easterYear),
mktime(0, 0, 0, $easterMonth, $easterDay + 50, $easterYear),
);

sort($holidays);

return
$holidays;
}
?>
1
Guillaume Dufrene
11 年前
我發現假日時間戳記計算和日光節約時間之間存在問題。
一篇關於此事的文章在 http://goo.gl/76t31 (僅有法文版本,抱歉)。

總而言之,今年 (2013) 復活節是在增加日光節約時間之前開始的 (發生在星期日 3:00)。這表示如果你執行 $easter + X,其中 x 是相當於一天的秒數、39 天或 50 天,結果不等於午夜時間戳記...

這裡有一個函數可以檢查午夜時間戳記是否等於假日

function isHoliday( $ts ) {
// 授權條款:創用 CC (BY)
// By Webpulser - http://goo.gl/76t31
$fixed_holidays = array( ’01-01′, ’01-05′, ’08-05′, ’14-07′, ’15-08′, ’11-11′, ’25-12′ );
$format = ‘d-m’;

$dm = date($format, $ts);
if ( in_array($dm, $fixed_holidays) ) return true;

$easter = easter_date( date(‘Y’, $ts) );
if ( date($format, $easter + 86400) == $dm ) return true;
if ( date($format, $easter + 3369600) == $dm ) return true;
if ( date($format, $easter + 4320000) == $dm ) return true;

return false;
}

請自由使用/修改。
1
alexandre dot php dot net at exmackina dot com
23 小時前
<?php

class DateUtils {
/**
* 判斷指定日期是否為法國(不含亞爾薩斯-摩澤爾地區)的國定假日。
*
* @param DateTime $date 要檢查的日期。
* @return bool 如果日期是國定假日則返回 True,否則返回 False。
*/
public static function isFrenchHoliday(DateTime $date): bool {

// 將要檢查的日期轉換為歐洲/巴黎時區 // 注意:這可能會影響日期,甚至與 UTC 時間相比年份也會不同
$dateToCheck = clone $date;
$dateToCheck->setTimezone(new DateTimeZone('Europe/Paris'));

$year = $dateToCheck->format('Y');
$easterDate = new DateTime('@'.easter_date($year), new DateTimeZone('UTC')); // 注意:若不使用 DateTimeZone('UTC'),從時間戳記建立的日期仍然會是 UTC 時間,但明確指定是個好習慣。
/*
easter_date() 會返回復活節的時間戳記,該時間戳記可轉換為當地時間 0:00,但基於 UTC 日期/時間!
例如,對於 2024-04-01,使用時間戳記建立的 DateTime 將會在 UTC 2024-03-31 23:00,在 UTC+1 的系統中才能得到正確的結果 (當地時間 0:00)
*/
$easterDate->setTimezone(new DateTimeZone('Europe/Paris'));

$holidays = [
// 固定假日
'01-01', // 元旦
'01-05', // 勞動節
'08-05', // 歐洲勝利日
'14-07', // 法國國慶日
'15-08', // 聖母升天節
'01-11', // 諸聖節
'11-11', // 停戰日
'25-12', // 聖誕節

// 可移動的假日
// 注意:復活節 (星期日) 未列為法國的國定假日
(clone $easterDate)->modify('+1 day')->format('d-m'), // 復活節星期一 (復活節 + 1 天)
(clone $easterDate)->add(new DateInterval('P39D'))->format('d-m'), // 耶穌升天節 (復活節 + 39 天)
// 五旬節在復活節後的第七個星期日慶祝,即 7x7 天,或 49 天...
// 注意:五旬節未列為法國的國定假日
(clone $easterDate)->add(new DateInterval('P50D'))->format('d-m'), // 五旬節星期一 (復活節 + 50 天)
];
// 注意:亞爾薩斯-摩澤爾地區有兩個額外的國定假日。
// 注意:在瓜德羅普、圭亞那、馬丁尼克、馬約特、留尼旺、聖巴泰勒米和聖馬丁,廢除奴隸制被紀念為法國國定假日 https://www.legifrance.gouv.fr/codes/section_lc/LEGITEXT000006072050/LEGISCTA000006160771/

return in_array($dateToCheck->format('d-m'), $holidays);
}
}
?>
<?php
class DateUtilsTest extends TestCase
{

public function
testIsFrenchHolidayReturnsFalseForNonHoliday()
{
$date = new DateTime('2023-09-27');
$this->assertFalse(DateUtils::isFrenchHoliday($date));
}

/**
* @dataProvider datesFor2024
*/
public function testIsFrenchHolidayReturnsTrueFor2024($dateString)
{
$date = new DateTime($dateString);
$this->assertTrue(DateUtils::isFrenchHoliday($date));
}

public function
datesFor2024()
{
// 來源:https://www.service-public.fr/particuliers/actualites/A15406
return [
[
'2024-01-01'], // 元旦
['2024-04-01'], // 復活節星期一
['2024-05-01'], // 勞動節
['2024-05-08'], // 歐洲勝利日
['2024-05-09'], // 耶穌升天節
['2024-05-20'], // 五旬節星期一
['2024-07-14'], // 法國國慶日
['2024-08-15'], // 聖母升天節
['2024-11-01'], // 諸聖節
['2024-11-11'], // 停戰日
['2024-12-25'], // 聖誕節
];
}

// public function testIsFrenchHolidayHandlesDatesAroundMidnight($dateString, $fromTimeZone, $toTimeZone, $expected)
// ...
}
?>
-1
phpuser
20 年前
如果加入一些 (int) 轉換,Bigtree 的演算法是正確的
<?php
function easter_date ($Year) {

/*
G 是黃金數 - 1
H 是 23 - 歲差 (模 30)
I 是 3 月 21 日到逾越節滿月的日子數
J 是逾越節滿月的星期幾 (0=星期日,
1=星期一, 等等)
L 是 3 月 21 日到逾越節滿月之前或當天星期日的日子數 (介於 -6 到 28 的數字)
*/


$G = $Year % 19;
$C = (int)($Year / 100);
$H = (int)($C - (int)($C / 4) - (int)((8*$C+13) / 25) + 19*$G + 15) % 30;
$I = (int)$H - (int)($H / 28)*(1 - (int)($H / 28)*(int)(29 / ($H + 1))*((int)(21 - $G) / 11));
$J = ($Year + (int)($Year/4) + $I + 2 - $C + (int)($C/4)) % 7;
$L = $I - $J;
$m = 3 + (int)(($L + 40) / 44);
$d = $L + 28 - 31 * ((int)($m / 4));
$y = $Year;
$E = mktime(0,0,0, $m, $d, $y);

return
$E;

}
?>
-3
adwil at live dot com
10 年前
嗨,最近我需要一個函數來取得線上商店的出貨日期,所以這就是了(為波蘭使用者準備好了,請為其他國家調整您的日期)

<?php
function getWorkday($date1,$workDays) {
$workDays = (int)$workDays;
if (
$workDays <= 0)
return
null;

$date1=strtotime('-1 day',strtotime($date1));

$lastYear = null;
$hol=array('01-01','01-06','05-01','05-03','08-15','11-01','11-11','12-25','12-26'); // 靜態假期的月份-日期陣列 (這些是波蘭的)
$i = 0;
while (
$i<=$workDays) {
$year = date('Y', $date1);
if (
$year !== $lastYear){
$lastYear = $year;
$easter = date('m-d', easter_date($year));
$date = strtotime($year . '-' . $easter); // 復活節
$easterSec = date('m-d', strtotime('+1 day', $date)); // 復活節星期一
$greens = date('m-d', strtotime('+49 days', $date)); // 五旬節
$cc = date('m-d', strtotime('+60 days', $date)); // 基督聖體聖血節
$hol[] = $easter;
$hol[] = $easterSec;
$hol[] = $greens;
$hol[] = $cc;
}
$weekDay=date('w',$date1);
if (!(
$weekDay==0 || $weekDay==6 || in_array(date('m-d',$date1),$hol)))
$i++;

$date1=strtotime('+1 day',$date1);
}
return
date('Y-m-d',$date1);
}
?>
To Top