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

Add vietnamese holidays #115

Merged
merged 26 commits into from
Jan 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d41c432
add Vietnamese holidays according to the standard calendar.
kevinb1989 Jan 18, 2024
5997d03
include Vietnamese holidays according to Chinese Calendar.
kevinb1989 Jan 19, 2024
95dc2b1
refactor the a Chinese calendar trait.
kevinb1989 Jan 19, 2024
145bff8
update the Lunar New Year's Eve.
kevinb1989 Jan 19, 2024
a7fdadc
re-add snapshots for countries other than Vietnam.
kevinb1989 Jan 19, 2024
6ad7eb8
use Vietnamese to name the holidays, English names commented.
kevinb1989 Jan 19, 2024
6ba1739
For Vietnam, use the country code of vn instead of vi.
kevinb1989 Jan 19, 2024
b7fe5c8
refactor according to PHPStan.
kevinb1989 Jan 19, 2024
2461db9
specify a type for the $timezone parameter.
kevinb1989 Jan 19, 2024
f6ca7c4
Refactor according to PHPStan.
kevinb1989 Jan 19, 2024
f07dccf
In Vietnam, a day before or after the Independence Day can be a publi…
kevinb1989 Jan 21, 2024
807e297
Merge branch 'main' into add-vietnamese-holidays
kevinb1989 Jan 21, 2024
adbedf9
work out some logics to calculate the extra day off for Independence …
kevinb1989 Jan 21, 2024
96f6c82
add a few test cases to make sure the Lunar New Year holiday in Vietn…
kevinb1989 Jan 22, 2024
873fa04
Add test cases for the holiday of independence.
kevinb1989 Jan 22, 2024
9dde2a8
add doc blocks.
kevinb1989 Jan 22, 2024
608bff9
remove empty line.
kevinb1989 Jan 22, 2024
16b7a4f
rename an instance variable.
kevinb1989 Jan 22, 2024
bd94b6d
add two more days to the Lunar Year Year holiday.
kevinb1989 Jan 24, 2024
4a6d3dc
refactor from Y/m/d to Y-m-d for Chinese Calendar.
kevinb1989 Jan 24, 2024
15569f1
Merge branch 'main' into add-vietnamese-holidays
kevinb1989 Jan 24, 2024
82dcfd9
add a few more test cases for Lunar New Year.
kevinb1989 Jan 24, 2024
5303d33
refactor the Lunar New Year holiday.
kevinb1989 Jan 24, 2024
6f20dd5
refactor and add a few more test cases.
kevinb1989 Jan 24, 2024
510b6f6
Merge branch 'main' into add-vietnamese-holidays
kevinb1989 Jan 27, 2024
f32f9a4
add translations for vietnam
kevinb1989 Jan 27, 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
16 changes: 16 additions & 0 deletions lang/vietnam/en/holidays.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"Tết Dương Lịch":"New Year's Day",
"Ngày Hai Mươi Chín Tết":"12-29 the previous year (in Chinese Calendar)",
"Ngày Ba Mươi Tết":"Lunar New Year's Eve (12-30 in Chinese Calendar)",
"Mùng Một Tết Âm Lịch":"Lunar New Year Day 1",
"Mùng Hai Tết Âm Lịch":"Lunar New Year Day 2",
"Mùng Ba Tết Âm Lịch":"Lunar New Year Day 3",
"Mùng Bốn Tết Âm Lịch":"Lunar New Year Day 4",
"Mùng Năm Tết Âm Lịch":"Lunar New Year Day 5",
"Ngày Giỗ Tổ Hùng Vương":"Hung Kings' Festival",
"Ngày Giải Phóng Miền Nam, Thống Nhất Đất Nước":"Day of Southern Liberation and National Reunification",
"Ngày Quốc Tế Lao Động":"Labour Day",
"Ngày Trước Quốc Khánh":"The Day Before Independence Day",
"Ngày Quốc Khánh":"Independence Day",
"Ngày Sau Quốc Khánh":"The Day After Independence Day"
}
39 changes: 39 additions & 0 deletions src/Calendars/ChineseCalendar.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace Spatie\Holidays\Calendars;

use Carbon\CarbonImmutable;
use DateTimeZone;
use IntlDateFormatter;

trait ChineseCalendar
kevinb1989 marked this conversation as resolved.
Show resolved Hide resolved
{
protected string $asianTimezone = 'Asia/Shanghai';

public function setTimezoneForChineseCalendar(string $asianTimezone): static
{
$this->asianTimezone = $asianTimezone;

return $this;
}

protected function chineseToGregorianDate(string $input, int $year): CarbonImmutable
kevinb1989 marked this conversation as resolved.
Show resolved Hide resolved
{
$timestamp = (int) $this->getFormatter()->parse($year . '-' . $input);

return (new CarbonImmutable())
->setTimeStamp($timestamp)
->setTimezone(new DateTimeZone($this->asianTimezone));
}

protected function getFormatter(): IntlDateFormatter
{
return new IntlDateFormatter(
locale: 'zh-CN@calendar=chinese',
dateType: IntlDateFormatter::SHORT,
timeType: IntlDateFormatter::NONE,
timezone: $this->asianTimezone,
calendar: IntlDateFormatter::TRADITIONAL
);
}
}
117 changes: 117 additions & 0 deletions src/Countries/Vietnam.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

namespace Spatie\Holidays\Countries;

use Carbon\CarbonImmutable;
use DateTimeZone;
use IntlDateFormatter;
use Spatie\Holidays\Calendars\ChineseCalendar;

class Vietnam extends Country
{
use ChineseCalendar;

public function countryCode(): string
{
return 'vn';
}

protected function allHolidays(int $year): array
{
return array_merge([
// New Year's Day
kevinb1989 marked this conversation as resolved.
Show resolved Hide resolved
'Tết Dương Lịch' => '01-01',
// Day of Southern Liberation and National Reunification
'Ngày Giải Phóng Miền Nam, Thống Nhất Đất Nước' => '04-30',
// Labour Day
'Ngày Quốc Tế Lao Động' => '05-01',
// Independence Day
'Ngày Quốc Khánh' => '09-02',
kevinb1989 marked this conversation as resolved.
Show resolved Hide resolved
], $this->variableHolidays($year));
}

/** @return array<string, CarbonImmutable> */
protected function variableHolidays(int $year): array
{
$this->setTimezoneForChineseCalendar('Asia/Ho_Chi_Minh');

return array_merge(
$this->getHungKingsFestival($year),
$this->getLunarNewYearHoliday($year),
$this->getTheExtraDayForIndependenceDay($year),
);
}

/** @return array<string, CarbonImmutable> */
protected function getHungKingsFestival(int $year): array
{
return [
// Hung Kings' Festival
'Ngày Giỗ Tổ Hùng Vương' => $this->chineseToGregorianDate('03-10', $year),
];
}

/** @return array<string, CarbonImmutable> */
protected function getLunarNewYearHoliday(int $year): array
{
$firstOfJanInChineseCalendar = $this->chineseToGregorianDate('01-01', $year);

return [
// 12-29 the previous year (in Chinese Calendar)
'Ngày Hai Mươi Chín Tết' => $firstOfJanInChineseCalendar->subDays(2),
// Lunar New Year's Eve (12-30 in Chinese Calendar)
'Ngày Ba Mươi Tết' => $firstOfJanInChineseCalendar->subDay(),
// Lunar New Year Day 1
'Mùng Một Tết Âm Lịch' => $firstOfJanInChineseCalendar,
// Lunar New Year Day 2
'Mùng Hai Tết Âm Lịch' => $firstOfJanInChineseCalendar->addDay(),
// Lunar New Year Day 3
'Mùng Ba Tết Âm Lịch' => $firstOfJanInChineseCalendar->addDays(2),
// Lunar New Year Day 4
'Mùng Bốn Tết Âm Lịch' => $firstOfJanInChineseCalendar->addDays(3),
// Lunar New Year Day 5
'Mùng Năm Tết Âm Lịch' => $firstOfJanInChineseCalendar->addDays(4),
];
}

/** @return array<string, CarbonImmutable> */
protected function getTheExtraDayForIndependenceDay(int $year): array
{
if ($year < 2021) {
return [];
}

$independenceDay = CarbonImmutable::parse("$year-09-02")
->setTimeZone("Asia/Ho_Chi_Minh");

if ($independenceDay->dayOfWeek == CarbonImmutable::MONDAY) {
return ['Ngày Sau Quốc Khánh' => $independenceDay->addDay()];
}

if ($independenceDay->dayOfWeek == CarbonImmutable::TUESDAY) {
return ['Ngày Trước Quốc Khánh' => $independenceDay->subDay()];
}

if ($independenceDay->dayOfWeek == CarbonImmutable::WEDNESDAY) {
return ['Ngày Trước Quốc Khánh' => $independenceDay->subDay()];
}

if ($independenceDay->dayOfWeek == CarbonImmutable::THURSDAY) {
return ['Ngày Sau Quốc Khánh' => $independenceDay->addDay()];
}

if ($independenceDay->dayOfWeek == CarbonImmutable::FRIDAY) {
return ['Ngày Trước Quốc Khánh' => $independenceDay->subDay()];
}

if ($independenceDay->dayOfWeek == CarbonImmutable::SATURDAY) {
return ['Ngày Trước Quốc Khánh' => $independenceDay->subDay()];
}

if ($independenceDay->dayOfWeek == CarbonImmutable::SUNDAY) {
return ['Ngày Sau Quốc Khánh' => $independenceDay->addDays(2)];
}

return [];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
[
{
"name": "T\u1ebft D\u01b0\u01a1ng L\u1ecbch",
"date": "2024-01-01"
},
{
"name": "Ng\u00e0y Hai M\u01b0\u01a1i Ch\u00edn T\u1ebft",
"date": "2024-02-08"
},
{
"name": "Ng\u00e0y Ba M\u01b0\u01a1i T\u1ebft",
"date": "2024-02-09"
},
{
"name": "M\u00f9ng M\u1ed9t T\u1ebft \u00c2m L\u1ecbch",
"date": "2024-02-10"
},
{
"name": "M\u00f9ng Hai T\u1ebft \u00c2m L\u1ecbch",
"date": "2024-02-11"
},
{
"name": "M\u00f9ng Ba T\u1ebft \u00c2m L\u1ecbch",
"date": "2024-02-12"
},
{
"name": "M\u00f9ng B\u1ed1n T\u1ebft \u00c2m L\u1ecbch",
"date": "2024-02-13"
},
{
"name": "M\u00f9ng N\u0103m T\u1ebft \u00c2m L\u1ecbch",
"date": "2024-02-14"
},
{
"name": "Ng\u00e0y Gi\u1ed7 T\u1ed5 H\u00f9ng V\u01b0\u01a1ng",
"date": "2024-04-18"
},
{
"name": "Ng\u00e0y Gi\u1ea3i Ph\u00f3ng Mi\u1ec1n Nam, Th\u1ed1ng Nh\u1ea5t \u0110\u1ea5t N\u01b0\u1edbc",
"date": "2024-04-30"
},
{
"name": "Ng\u00e0y Qu\u1ed1c T\u1ebf Lao \u0110\u1ed9ng",
"date": "2024-05-01"
},
{
"name": "Ng\u00e0y Qu\u1ed1c Kh\u00e1nh",
"date": "2024-09-02"
},
{
"name": "Ng\u00e0y Sau Qu\u1ed1c Kh\u00e1nh",
"date": "2024-09-03"
}
]
57 changes: 57 additions & 0 deletions tests/Countries/VietnamTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace Spatie\Holidays\Tests\Countries;

use Carbon\CarbonImmutable;
use Spatie\Holidays\Countries\Vietnam;
use Spatie\Holidays\Holidays;

it('can calculate vietnamese holidays', function () {
CarbonImmutable::setTestNowAndTimezone('2024-01-01', 'Asia/Ho_Chi_Minh');

$holidays = Holidays::for(country: 'vn')->get();

expect($holidays)
->toBeArray()
->not()->toBeEmpty();

expect(formatDates($holidays))->toMatchSnapshot();
});

it('can calculate the Lunar New Year holiday', function ($year, $expectedHoliday) {
CarbonImmutable::setTestNowAndTimezone("{$year}-01-01", 'Asia/Ho_Chi_Minh');

$holidays = Holidays::for(country: 'vn')->get();

expect($holidays)
->toBeArray()
->not()->toBeEmpty();

$lunarNewYearHoliday = array_map(fn ($date) => $date['date'], formatDates($holidays));

expect($lunarNewYearHoliday)->toContain(...$expectedHoliday);
})->with([
['year' => 2023, 'expected_holiday' => ['2023-01-20', '2023-01-21', '2023-01-22', '2023-01-23', '2023-01-24', '2023-01-25', '2023-01-26']],
['year' => 2022, 'expected_holiday' => ['2022-01-30', '2022-01-31', '2022-02-01', '2022-02-02', '2022-02-03', '2022-02-04', '2022-02-05']],
['year' => 2021, 'expected_holiday' => ['2021-02-10', '2021-02-11', '2021-02-12', '2021-02-13', '2021-02-14', '2021-02-15', '2021-02-16']],
['year' => 2020, 'expected_holiday' => ['2020-01-23', '2020-01-24', '2020-01-25', '2020-01-26', '2020-01-27', '2020-01-28', '2020-01-29']],
['year' => 2019, 'expected_holiday' => ['2019-02-03', '2019-02-04', '2019-02-05', '2019-02-06', '2019-02-07', '2019-02-08', '2019-02-08']],
]);

it('can calculate the holiday of independence', function ($year, $expectedHoliday) {
CarbonImmutable::setTestNowAndTimezone("{$year}-01-01", 'Asia/Ho_Chi_Minh');

$holidays = Holidays::for(country: 'vn')->get();

expect($holidays)
->toBeArray()
->not()->toBeEmpty();

$dates = array_map(fn ($date) => $date['date'], formatDates($holidays));

expect($dates)->toContain(...$expectedHoliday);
})->with([
['year' => 2023, 'expected_holiday' => ['2023-09-01', '2023-09-02']],
['year' => 2022, 'expected_holiday' => ['2022-09-01', '2022-09-02']],
['year' => 2021, 'expected_holiday' => ['2021-09-02', '2021-09-03']],
]);
Loading