Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Islamic calendar #214

Merged
merged 34 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
c818d84
add Islamic trait & contract
Nielsvanpach Feb 21, 2024
30fffae
bump php version
Nielsvanpach Feb 21, 2024
dca2942
wip: turkey refactor
Nielsvanpach Feb 21, 2024
d8d86aa
refactor Bahrain
Nielsvanpach Feb 21, 2024
7450fb6
wip: turkey refactor
Nielsvanpach Feb 21, 2024
db02e85
get Turkey in same format as other country classes
Nielsvanpach Feb 21, 2024
7a0a8ef
add Eve dates for Turkey
Nielsvanpach Feb 21, 2024
df81e49
Fix styling
Nielsvanpach Feb 21, 2024
e003bf4
handle lunar holidays that can happen twice a year
Nielsvanpach Mar 11, 2024
683e399
handle more edge cases
Nielsvanpach Mar 11, 2024
e1df42f
Fix styling
Nielsvanpach Mar 11, 2024
98a6fc5
remove 8.1
Nielsvanpach Mar 11, 2024
13cf381
fix Turkey
Nielsvanpach Mar 21, 2024
bbfdf94
Fix styling
Nielsvanpach Mar 21, 2024
07613d7
phpstan changes
Nielsvanpach Mar 21, 2024
cc24837
Fix styling
Nielsvanpach Mar 21, 2024
3be5393
refactor code for readability
Nielsvanpach Mar 22, 2024
af20753
refactor Bahrain too
Nielsvanpach Mar 22, 2024
04e8299
Fix styling
Nielsvanpach Mar 22, 2024
0c1c5e5
run 8.1 again
Nielsvanpach Mar 22, 2024
97c3c1a
edit phpstan runner
Nielsvanpach Mar 22, 2024
3529fac
handle new phpstan issues
Nielsvanpach Mar 22, 2024
a920d35
ignore weird phpstan error
Nielsvanpach Mar 22, 2024
ac47d08
use a fixed version for phpstan
Nielsvanpach Mar 22, 2024
d77fd5a
rename for Egypt
Nielsvanpach Mar 22, 2024
f45c884
update Egypt
Nielsvanpach Mar 22, 2024
4dd9815
Fix styling
Nielsvanpach Mar 22, 2024
20cc674
change signature
Nielsvanpach Mar 22, 2024
048ca87
fix phpstan version
Nielsvanpach Mar 22, 2024
0bb161f
use Islamic contract on Albania
Nielsvanpach Mar 22, 2024
ffa7382
implement Islamic interface on Syria
Nielsvanpach Mar 22, 2024
84538f4
phpstan
Nielsvanpach Mar 22, 2024
be4354c
Merge branch 'main' into refactor/islamic-calendar
Nielsvanpach Mar 22, 2024
69ed981
phpstan
Nielsvanpach Mar 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/phpstan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
php-version: '8.1'
coverage: none

- name: Install composer dependencies
Expand All @@ -21,4 +21,4 @@ jobs:
COMPOSER_AUTH: ${{ secrets.COMPOSER_AUTH }}

- name: Run PHPStan
run: ./vendor/bin/phpstan --error-format=github
run: ./vendor/bin/phpstan
28 changes: 28 additions & 0 deletions lang/turkey/tr/holidays.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"New Year's Day": "Yılbaşı",
"Eid al-Fitr Eve": "Ramazan Bayramı Arifesi",
"Eid al-Fitr": "Ramazan Bayramı 1. Gün",
"Eid al-Fitr Day 2": "Ramazan Bayramı 2. Gün",
"Eid al-Fitr Day 3": "Ramazan Bayramı 3. Gün",
"National Sovereignty and Children's Day": "Ulusal Egemenlik ve Çocuk Bayramı",
"Labor and Solidarity Day": "Emek ve Dayanışma Günü",
"Commemoration of Atatürk, Youth and Sports Day": "Atatürk'ü Anma, Gençlik ve Spor Bayramı",
"Eid al-Adha Eve": "Kurban Bayramı Arifesi",
"Eid al-Adha": "Kurban Bayramı 1. Gün",
"Eid al-Adha Day 2": "Kurban Bayramı 2. Gün",
"Eid al-Adha Day 3": "Kurban Bayramı 3. Gün",
"Eid al-Adha Day 4": "Kurban Bayramı 4. Gün",
"Democracy and National Unity Day": "Demokrasi ve Millî Birlik Günü",
"Victory Day": "Zafer Bayramı",
"Republic Day Eve": "Cumhuriyet Bayramı Arifesi",
"Republic Day": "Cumhuriyet Bayramı",
"2. Eid al-Fitr Eve": "2. Ramazan Bayramı Arifesi",
"2. Eid al-Fitr": "2. Ramazan Bayramı 1. Gün",
"2. Eid al-Fitr Day 2": "2. Ramazan Bayramı 2. Gün",
"2. Eid al-Fitr Day 3": "2. Ramazan Bayramı 3. Gün",
"2. Eid al-Adha Eve": "2. Kurban Bayramı Arifesi",
"2. Eid al-Adha": "2. Kurban Bayramı 1. Gün",
"2. Eid al-Adha Day 2": "2. Kurban Bayramı 2. Gün",
"2. Eid al-Adha Day 3": "2. Kurban Bayramı 3. Gün",
"2. Eid al-Adha Day 4": "2. Kurban Bayramı 4. Gün"
}
49 changes: 47 additions & 2 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
@@ -1,13 +1,58 @@
parameters:
ignoreErrors:
-
message: "#^Access to undefined constant Spatie\\\\Holidays\\\\Countries\\\\Albania\\:\\:arafat\\.$#"
count: 1
path: src/Countries/Albania.php

-
message: "#^Access to undefined constant Spatie\\\\Holidays\\\\Countries\\\\Albania\\:\\:ashura\\.$#"
count: 1
path: src/Countries/Albania.php

-
message: "#^Access to undefined constant Spatie\\\\Holidays\\\\Countries\\\\Albania\\:\\:islamicNewYear\\.$#"
count: 1
path: src/Countries/Albania.php

-
message: "#^Access to undefined constant Spatie\\\\Holidays\\\\Countries\\\\Albania\\:\\:prophetMuhammadBirthday\\.$#"
count: 1
path: src/Countries/Albania.php

-
message: "#^Argument of an invalid type Carbon\\\\CarbonPeriod supplied for foreach, only iterables are supported\\.$#"
count: 1
path: src/Countries/Country.php

-
message: "#^Argument of an invalid type array\\<int, string\\>\\|false supplied for foreach, only iterables are supported\\.$#"
count: 1
path: src/Countries/Country.php

-
message: "#^Ternary operator condition is always true\\.$#"
count: 3
message: "#^Binary operation \"\\+\" between non\\-falsy\\-string and 1 results in an error\\.$#"
count: 1
path: src/Countries/Country.php

-
message: "#^Access to undefined constant Spatie\\\\Holidays\\\\Countries\\\\Turkey\\:\\:arafat\\.$#"
count: 1
path: src/Countries/Turkey.php

-
message: "#^Access to undefined constant Spatie\\\\Holidays\\\\Countries\\\\Turkey\\:\\:ashura\\.$#"
count: 1
path: src/Countries/Turkey.php

-
message: "#^Access to undefined constant Spatie\\\\Holidays\\\\Countries\\\\Turkey\\:\\:islamicNewYear\\.$#"
count: 1
path: src/Countries/Turkey.php

-
message: "#^Access to undefined constant Spatie\\\\Holidays\\\\Countries\\\\Turkey\\:\\:prophetMuhammadBirthday\\.$#"
count: 1
path: src/Countries/Turkey.php

-
Expand Down
2 changes: 2 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ parameters:

ignoreErrors:
- '#Unsafe usage of new static#'
- '#Cannot call method startOfDay\(\) on Carbon\\CarbonImmutable\|null#'
- '#Cannot call method addDays\(\) on Carbon\\CarbonImmutable\|null#'
141 changes: 141 additions & 0 deletions src/Calendars/IslamicCalendar.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php

namespace Spatie\Holidays\Calendars;

use Carbon\CarbonImmutable;
use Carbon\CarbonPeriod;
use Carbon\Exceptions\InvalidFormatException;
use Spatie\Holidays\Countries\Country;
use Spatie\Holidays\Exceptions\InvalidYear;

/** @mixin Country */
trait IslamicCalendar
{
/** @return array<CarbonPeriod> */
public function eidAlFitr(int $year, int $totalDays = 3): array
{
return $this->getMultiDayHoliday(self::eidAlFitr, $year, $totalDays);
}

/** @return array<CarbonPeriod> */
public function eidAlAdha(int $year, int $totalDays = 4): array
{
return $this->getMultiDayHoliday(self::eidAlAdha, $year, $totalDays);
}

/** @return array<CarbonPeriod> */
protected function ashura(int $year, int $totalDays = 2): array
{
return $this->getMultiDayHoliday(self::ashura, $year, $totalDays);
}

protected function arafat(int $year): CarbonImmutable
{
return $this->getSingleDayHoliday(self::arafat, $year);
}

protected function islamicNewYear(int $year): CarbonImmutable
{
return $this->getSingleDayHoliday(self::islamicNewYear, $year);
}

protected function prophetMuhammadBirthday(int $year): CarbonImmutable
{
return $this->getSingleDayHoliday(self::prophetMuhammadBirthday, $year);
}

/** @param array<string> $collection */
protected function getSingleDayHoliday(array $collection, int $year): CarbonImmutable
{
$date = $collection[$year] ?? null;

if ($date === null) {
throw InvalidYear::range($this->countryCode(), 1970, 2037);
}

$date = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}")?->startOfDay();

if ($date === null) {
throw new InvalidFormatException('Invalid date for holiday');
}

return $date;
}

/**
* @param array<string|array<string>> $collection
* @return array<CarbonPeriod>
*/
protected function getMultiDayHoliday(array $collection, int $year, int $totalDays): array
{
$date = $collection[$year] ?? null;

if ($date === null) {
throw InvalidYear::range($this->countryCode(), 1970, 2037);
}

$overlap = $this->getOverlapping($collection, $year, $totalDays);

if ($overlap) {
$period = $this->createPeriod($overlap, $year - 1, $totalDays);

$date = [$period, $date];
}

if (! is_array($date)) {
return [$this->createPeriod($date, $year, $totalDays)];
}

// Twice a year
$periods = [];
$dates = $date;

/** @var CarbonPeriod|string $date */
foreach ($dates as $date) {
if ($date instanceof CarbonPeriod) {
$periods[] = $date;

continue;
}

$periods[] = $this->createPeriod($date, $year, $totalDays);
}

return $periods;
}

protected function createPeriod(string $date, int $year, int $totalDays): CarbonPeriod
{
$start = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}")?->startOfDay();
$end = $start->addDays($totalDays - 1)->startOfDay();

return CarbonPeriod::create($start, '1 day', $end);
}

/** @param array<string|array<string>> $collection */
protected function getOverlapping(array $collection, int $year, int $totalDays): ?string
{
if ($year === 1970) {
return null;
}

$date = $collection[$year - 1] ?? null;

if ($date === null) {
throw InvalidYear::range($this->countryCode(), 1970, 2037);
}

if (is_array($date)) {
$date = end($date);
}

$start = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}")?->startOfDay();
$end = $start->addDays($totalDays - 1)->startOfDay();

if ($end->year !== $year) {
return (string) $date;
}

return null;
}
}
15 changes: 4 additions & 11 deletions src/Concerns/Translatable.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,19 @@ trait Translatable
{
public function translate(string $country, string $name, ?string $locale = null): string
{
if ($locale === null) {
return $name;

}

if ($locale === $this->defaultLocale()) {
return $name;
}

$locale = $locale ?? $this->defaultLocale();

$countryName = strtolower($country);
$filePath = __DIR__."/../../lang/{$countryName}/{$locale}/holidays.json";

if (file_exists($filePath)) {
$content = file_get_contents($filePath);
} else {
throw InvalidLocale::notFound($country, $locale);
return $name;
}

if ($content === false) {
Expand All @@ -33,10 +30,6 @@ public function translate(string $country, string $name, ?string $locale = null)
/** @var array<string, string> $data */
$data = json_decode($content, true);

if (! isset($data[$name])) {
return $name;
}

return $data[$name];
return $data[$name] ?? $name;
}
}
12 changes: 12 additions & 0 deletions src/Contracts/Islamic.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Spatie\Holidays\Contracts;

use Carbon\CarbonImmutable;
use Carbon\CarbonPeriod;

interface Islamic
{
/** @return array<string, string|CarbonImmutable|CarbonPeriod> */
public function islamicHolidays(int $year): array;
}
Loading