92 Commits

Author SHA1 Message Date
5166d6ce3b Merge pull request 'feature/hk-holiday-support' (#2) from feature/hk-holiday-support into master
Reviewed-on: #2
2026-04-27 05:14:45 +00:00
526d99f193 docs: add data generation, import, and extension guide to README
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 12:53:44 +08:00
72ab05df3f docs: update README to cover Hong Kong holiday data
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 12:51:35 +08:00
05a1dca074 feat: add Hong Kong public holiday support
- Add scripts/fetch_hk.py to fetch HK holidays from 1823.gov.hk
- Make generate_ics() cal_name/cal_desc configurable
- Refactor update.py with REGIONS config; support --region cn|hk flag
- Generate hk/{year}.json and hk/{year}.ics under hk/ subdirectory

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 12:09:34 +08:00
c60002b782 Merge pull request 'add 2026 CN holiday info' (#1) from hotfix/add_2026_CN_holiday into master
Reviewed-on: #1
2026-01-05 05:08:59 +00:00
95df17c865 add 2026 CN holiday info 2026-01-05 13:05:25 +08:00
renovate[bot]
29869ddebf chore(deps): update dependency coverage to v7.6.9 (#248)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-06 16:22:10 +00:00
renovate[bot]
54784bad95 chore(deps): update dependency pytest to v8.3.4 (#247)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-01 18:06:34 +00:00
renovate[bot]
56b88184f3 chore(deps): update dependency tqdm to v4.67.1 (#246)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 01:57:20 +00:00
renovate[bot]
a39828d0d0 chore(deps): update dependency coverage to v7.6.8 (#245)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-24 07:45:59 +00:00
renovate[bot]
2ea4249b95 chore(deps): update dependency icalendar to v6.1.0 (#235)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-23 01:38:59 +00:00
Kwok
5046df59ec test: update years in description_parsing_cases.json (#244) 2024-11-17 00:42:04 +08:00
renovate[bot]
dc9b5e2ccf chore(deps): pin dependencies 2024-11-16 14:48:27 +08:00
NateScarlet
1d5fb6465e chore: update renovate config 2024-11-16 14:47:22 +08:00
NateScarlet
0c2759c89d chore(deps): update dependency icalendar to v6.0.1 2024-11-16 14:35:15 +08:00
NateScarlet
cd46049bba docs: remove code climate badges 2024-11-16 14:18:10 +08:00
NateScarlet
b3920d0395 Merge branch 'master' of https://github.com/NateScarlet/holiday-cn 2024-11-16 14:12:22 +08:00
NateScarlet
412805386b docs: add jsdelivr badge 2024-11-16 14:12:09 +08:00
renovate[bot]
72dbe5a3a0 chore(deps): update dependency coverage to v7.6.7 (#242)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-15 18:08:37 +00:00
renovate[bot]
acf9c753e7 chore(deps): update dependency coverage to v7.6.5 (#241)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-14 21:36:53 +00:00
NateScarlet
169c3e5d1b docs: update related papers 2024-11-12 21:04:09 +08:00
NateScarlet
9567f22846 chore(deps): update dependency black to v24.10.0 2024-11-12 20:54:44 +08:00
renovate[bot]
cf5e394103 chore(deps): update dependency coverage to v7 2024-11-12 20:49:50 +08:00
renovate[bot]
69146c43de chore(deps): update dependency pytest to v8 2024-11-12 20:47:46 +08:00
NateScarlet
0dedd4f863 ci: update actions/setup-python to v5 2024-11-12 20:44:50 +08:00
NateScarlet
f3e07139d0 ci: update actions/checkout to v4 2024-11-12 20:44:09 +08:00
NateScarlet
97434adcac chore(deps): update python to 3.12 2024-11-12 20:41:06 +08:00
GitHub Actions
6d06f199f8 chore(release): update holiday data
[skip ci]
2024-11-12 12:30:13 +00:00
NateScarlet
a7a1065c70 fix: handle new description 2024-11-12 20:29:26 +08:00
NateScarlet
aefd2f1458 docs: add alternative jsdelivr url 2024-11-11 15:50:44 +08:00
renovate[bot]
5a57998efa chore(deps): update dependency tqdm to v4.67.0 2024-11-06 21:44:51 +00:00
renovate[bot]
d4597e6cf3 chore(deps): update dependency tqdm to v4.66.6 2024-10-28 15:21:23 +00:00
renovate[bot]
14cd952eaa chore(deps): update dependency tqdm to v4.66.5 2024-08-04 04:43:59 +00:00
renovate[bot]
2f78d9d49b chore(deps): update dependency requests to v2.32.3 2024-06-17 19:33:36 +00:00
renovate[bot]
fd01b1d32a chore(deps): update dependency requests to v2.32.2 [security] 2024-06-17 16:09:21 +00:00
renovate[bot]
d5d050fc94 chore(deps): update dependency tqdm to v4.66.4 2024-05-03 03:16:11 +00:00
renovate[bot]
267bfda287 chore(deps): update dependency tqdm to v4.66.2 2024-02-10 21:05:08 +00:00
NateScarlet
ca608d54dd docs: update ghproxy url 2024-01-28 02:55:15 +08:00
NateScarlet
1f8bd77f1c docs: update ghproxy url 2024-01-28 02:46:43 +08:00
NateScarlet
ccea60b3ce docs: add notice about weekend 2024-01-18 19:38:00 +08:00
renovate[bot]
35d55cda4e chore(deps): update dependency beautifulsoup4 to v4.12.3 2024-01-17 21:54:48 +00:00
NateScarlet
385a47c4be docs: update maintenance year 2024-01-03 12:13:56 +08:00
GitHub Actions
87eda11391 chore(release): update holiday data
[skip ci]
2024-01-01 12:13:45 +00:00
renovate[bot]
224b285ae7 chore(deps): update dependency pytest to v7.4.4 2023-12-31 15:52:21 +00:00
renovate[bot]
f4f6d0f174 chore(deps): update dependency black to v23.12.1 2023-12-23 04:27:00 +00:00
renovate[bot]
a08257d14a chore(deps): update dependency black to v23.12.0 2023-12-12 10:18:34 +00:00
renovate[bot]
cc1887d463 chore(deps): update dependency black to v23.11.0 2023-11-08 10:49:55 +00:00
GitHub Actions
b00e2d38a8 chore(release): update holiday data
[skip ci]
2023-10-25 03:11:15 +00:00
NateScarlet
74303b42dd fix: should not check paper url
gov.cn change url frequently
2023-10-25 11:10:37 +08:00
renovate[bot]
00f45649fa chore(deps): update dependency pytest to v7.4.3 2023-10-24 21:51:20 +00:00
renovate[bot]
c05f95b517 chore(deps): update dependency black to v23.10.1 2023-10-24 01:21:05 +00:00
renovate[bot]
26bf12e7c0 chore(deps): update dependency black to v23.10.0 2023-10-17 21:21:53 +00:00
NateScarlet
f439a6750a ci: migrate hub to gh
https://github.com/actions/runner-images/issues/8362
2023-10-08 00:35:13 +08:00
renovate[bot]
85a0a0085b chore(deps): update dependency black to v23.9.1 2023-09-11 07:08:43 +00:00
renovate[bot]
e2c18f51eb chore(deps): update dependency black to v23.9.0 2023-09-09 07:12:17 +00:00
renovate[bot]
122cdf65f3 chore(deps): update dependency pytest to v7.4.2 2023-09-07 21:22:05 +00:00
renovate[bot]
740104579c chore(deps): update dependency icalendar to v4.1.1 2023-09-06 23:00:47 +00:00
renovate[bot]
0533af04bd chore(deps): update dependency pytest to v7.4.1 2023-09-02 19:55:45 +00:00
NateScarlet
c7dc8a194e chore(release): update holiday data
[skip ci]
2023-08-17 23:05:29 +08:00
NateScarlet
cd791e1893 fix: follow gov.cn api change 2023-08-17 22:48:17 +08:00
renovate[bot]
8e4cf83082 chore(deps): update dependency tqdm to v4.66.1 2023-08-10 15:54:48 +00:00
renovate[bot]
ac0ef28ba7 chore(deps): update dependency tqdm to v4.66.0 2023-08-09 17:54:55 +00:00
renovate[bot]
eb94de4808 chore(deps): update dependency tqdm to v4.65.2 2023-08-09 03:20:15 +00:00
renovate[bot]
2f21068a0c chore(deps): update dependency tqdm to v4.65.1 2023-08-08 13:45:37 +00:00
renovate[bot]
932344b48a chore(deps): update dependency black to v23.7.0 2023-07-11 04:54:53 +00:00
renovate[bot]
009e5b342e chore(deps): update dependency pytest to v7.4.0 2023-06-23 16:15:00 +00:00
renovate[bot]
2d410be0a3 chore(deps): update dependency pytest to v7.3.2 2023-06-11 00:27:41 +00:00
renovate[bot]
ef70020a73 chore(deps): update dependency requests to v2.31.0 2023-05-22 21:28:37 +00:00
NateScarlet
d1369f1c05 fix: follow site dom change 2023-05-15 01:58:42 +08:00
NateScarlet
868d0eb712 fix: follow site dom change 2023-05-14 14:24:31 +08:00
renovate[bot]
43ade74e48 chore(deps): update dependency requests to v2.30.0 2023-05-04 17:58:06 +00:00
renovate[bot]
cb9d9297a2 chore(deps): update dependency requests to v2.29.0 2023-04-26 23:04:52 +00:00
renovate[bot]
7225f513be chore(deps): update dependency pytest to v7.3.1 2023-04-14 22:39:37 +00:00
renovate[bot]
df25c19f3c chore(deps): update dependency pytest to v7.3.0 2023-04-08 23:38:42 +00:00
renovate[bot]
4611a6451d chore(deps): update dependency beautifulsoup4 to v4.12.2 2023-04-07 18:31:49 +00:00
renovate[bot]
cd3a247ae7 chore(deps): update dependency beautifulsoup4 to v4.12.1 2023-04-05 21:04:16 +00:00
renovate[bot]
85c1438c7b chore(deps): update dependency black to v23.3.0 2023-03-29 10:30:53 +00:00
renovate[bot]
6ab5c14c2a chore(deps): update dependency beautifulsoup4 to v4.12.0 2023-03-20 15:29:25 +00:00
renovate[bot]
e6c29e0bcd chore(deps): update dependency tqdm to v4.65.0 2023-03-04 11:05:47 +00:00
renovate[bot]
5257ede632 chore(deps): update dependency pytest to v7.2.2 2023-03-04 08:00:36 +00:00
NateScarlet
f5696c2f52 chore(deps): upgrade black to v23.1.0 2023-02-09 22:46:41 +08:00
renovate[bot]
82e0ae1a60 chore(deps): update dependency beautifulsoup4 to v4.11.2 2023-02-01 02:16:22 +00:00
renovate[bot]
5b07fee6bb chore(deps): update dependency pytest to v7.2.1 2023-01-14 15:36:10 +00:00
renovate[bot]
5fce379744 chore(deps): update dependency requests to v2.28.2 2023-01-12 20:57:47 +00:00
NateScarlet
9b5f10d118 docs: update stale badge
[skip ci]
2023-01-03 12:42:12 +08:00
GitHub Actions
7a1da4851c chore(release): update holiday data
[skip ci]
2023-01-01 12:12:54 +00:00
renovate[bot]
f0543c808f chore(deps): update dependency black to v22.12.0 2022-12-09 19:38:03 +00:00
NateScarlet
d2805ad091 revert: chore(release): update holiday data
This reverts commit 747966e6db.
2022-12-09 20:47:21 +08:00
NateScarlet
a2b3b609f8 chore: run formatter 2022-12-09 19:12:25 +08:00
NateScarlet
946c5b4112 chore: update path in scripts 2022-12-09 17:42:01 +08:00
GitHub Actions
747966e6db chore(release): update holiday data
[skip ci]
2022-12-09 08:53:54 +00:00
NateScarlet
ef9f9cd5e3 chore: move python code to /scripts 2022-12-09 16:52:02 +08:00
64 changed files with 2140 additions and 705 deletions

View File

@@ -11,12 +11,12 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-python@v4 - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5
with: with:
python-version: '3.8' python-version: '3.12'
- name: Install dependencies - name: Install dependencies
run: pip install -r requirements.txt -r dev-requirements.txt run: pip install -r dev-requirements.txt
- name: Setup git user - name: Setup git user
run: | run: |
git config user.name "GitHub Actions" git config user.name "GitHub Actions"
@@ -29,10 +29,10 @@ jobs:
if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request' }} if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request' }}
env: env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
run: coverage run -a ./update.py --release run: coverage run -a ./scripts/update.py --release
- name: Update - name: Update
if: ${{ !(github.ref == 'refs/heads/master' && github.event_name != 'pull_request') }} if: ${{ !(github.ref == 'refs/heads/master' && github.event_name != 'pull_request') }}
run: coverage run -a ./update.py run: coverage run -a ./scripts/update.py
# FIXME # FIXME
#- name: Report coverage #- name: Report coverage
# env: # env:

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,7 +3,7 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2007.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2007.json",
"year": 2007, "year": 2007,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2008-03/28/content_1761.htm" "http://www.gov.cn/zhengce/zhengceku/2008-03/28/content_1761.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,7 +3,7 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2008.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2008.json",
"year": 2008, "year": 2008,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2008-03/28/content_1645.htm" "http://www.gov.cn/zhengce/zhengceku/2008-03/28/content_1645.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,7 +3,7 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2009.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2009.json",
"year": 2009, "year": 2009,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2008-12/10/content_1572.htm" "http://www.gov.cn/zhengce/zhengceku/2008-12/10/content_1572.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,7 +3,7 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2010.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2010.json",
"year": 2010, "year": 2010,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2009-12/08/content_1476.htm" "http://www.gov.cn/zhengce/zhengceku/2009-12/08/content_1476.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,7 +3,7 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2011.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2011.json",
"year": 2011, "year": 2011,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2010-12/10/content_1423.htm" "http://www.gov.cn/zhengce/zhengceku/2010-12/10/content_1423.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,7 +3,7 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2012.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2012.json",
"year": 2012, "year": 2012,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2011-12/06/content_1411.htm" "http://www.gov.cn/zhengce/zhengceku/2011-12/06/content_1411.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,7 +3,7 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2013.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2013.json",
"year": 2013, "year": 2013,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2012-12/10/content_1353.htm" "http://www.gov.cn/zhengce/zhengceku/2012-12/10/content_1353.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,7 +3,7 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2014.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2014.json",
"year": 2014, "year": 2014,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2014-01/02/content_1194.htm" "http://www.gov.cn/zhengce/zhengceku/2014-01/02/content_1194.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,8 +3,8 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2015.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2015.json",
"year": 2015, "year": 2015,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2014-12/16/content_9302.htm", "http://www.gov.cn/zhengce/zhengceku/2014-12/16/content_9302.htm",
"http://www.gov.cn/zhengce/content/2015-05/13/content_9742.htm" "http://www.gov.cn/zhengce/zhengceku/2015-05/13/content_9742.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,7 +3,7 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2016.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2016.json",
"year": 2016, "year": 2016,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2015-12/10/content_10394.htm" "http://www.gov.cn/zhengce/zhengceku/2015-12/10/content_10394.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,7 +3,7 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2017.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2017.json",
"year": 2017, "year": 2017,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2016-12/01/content_5141603.htm" "http://www.gov.cn/zhengce/zhengceku/2016-12/01/content_5141603.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,7 +3,7 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2018.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2018.json",
"year": 2018, "year": 2018,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2017-11/30/content_5243579.htm" "http://www.gov.cn/zhengce/zhengceku/2017-11/30/content_5243579.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,8 +3,8 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2019.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2019.json",
"year": 2019, "year": 2019,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2018-12/06/content_5346276.htm", "http://www.gov.cn/zhengce/zhengceku/2018-12/06/content_5346276.htm",
"http://www.gov.cn/zhengce/content/2019-03/22/content_5375877.htm" "http://www.gov.cn/zhengce/zhengceku/2019-03/22/content_5375877.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,8 +3,8 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2020.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2020.json",
"year": 2020, "year": 2020,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2019-11/21/content_5454164.htm", "http://www.gov.cn/zhengce/zhengceku/2019-11/21/content_5454164.htm",
"http://www.gov.cn/zhengce/content/2020-01/27/content_5472352.htm" "http://www.gov.cn/zhengce/zhengceku/2020-01/27/content_5472352.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,7 +3,7 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2021.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2021.json",
"year": 2021, "year": 2021,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2020-11/25/content_5564127.htm" "http://www.gov.cn/zhengce/zhengceku/2020-11/25/content_5564127.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,7 +3,7 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2022.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2022.json",
"year": 2022, "year": 2022,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2021-10/25/content_5644835.htm" "http://www.gov.cn/zhengce/zhengceku/2021-10/25/content_5644835.htm"
], ],
"days": [ "days": [
{ {

View File

@@ -8,7 +8,7 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD

View File

@@ -3,7 +3,7 @@
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2023.json", "$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2023.json",
"year": 2023, "year": 2023,
"papers": [ "papers": [
"http://www.gov.cn/zhengce/content/2022-12/08/content_5730844.htm" "http://www.gov.cn/zhengce/zhengceku/2022-12/08/content_5730844.htm"
], ],
"days": [ "days": [
{ {

121
2024.ics Normal file
View File

@@ -0,0 +1,121 @@
BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
CLASS:PUBLIC
X-WR-CALDESC:中国法定节假日数据,自动每日抓取国务院公
告。
X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE
TZID:Asia/Shanghai
BEGIN:STANDARD
DTSTART:19700101T000000
TZOFFSETFROM:+0800
TZOFFSETTO:+0800
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
SUMMARY:元旦假期
DTSTART;VALUE=DATE:20240101
DTEND;VALUE=DATE:20240102
DTSTAMP;VALUE=DATE:20240101
UID:2024-01-01/2024-01-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20240204
DTEND;VALUE=DATE:20240205
DTSTAMP;VALUE=DATE:20240204
UID:2024-02-04/2024-02-05/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:春节假期
DTSTART;VALUE=DATE:20240210
DTEND;VALUE=DATE:20240218
DTSTAMP;VALUE=DATE:20240210
UID:2024-02-10/2024-02-18/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20240218
DTEND;VALUE=DATE:20240219
DTSTAMP;VALUE=DATE:20240218
UID:2024-02-18/2024-02-19/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:清明节假期
DTSTART;VALUE=DATE:20240404
DTEND;VALUE=DATE:20240407
DTSTAMP;VALUE=DATE:20240404
UID:2024-04-04/2024-04-07/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补清明节假期)
DTSTART;VALUE=DATE:20240407
DTEND;VALUE=DATE:20240408
DTSTAMP;VALUE=DATE:20240407
UID:2024-04-07/2024-04-08/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补劳动节假期)
DTSTART;VALUE=DATE:20240428
DTEND;VALUE=DATE:20240429
DTSTAMP;VALUE=DATE:20240428
UID:2024-04-28/2024-04-29/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:劳动节假期
DTSTART;VALUE=DATE:20240501
DTEND;VALUE=DATE:20240506
DTSTAMP;VALUE=DATE:20240501
UID:2024-05-01/2024-05-06/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补劳动节假期)
DTSTART;VALUE=DATE:20240511
DTEND;VALUE=DATE:20240512
DTSTAMP;VALUE=DATE:20240511
UID:2024-05-11/2024-05-12/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:端午节假期
DTSTART;VALUE=DATE:20240610
DTEND;VALUE=DATE:20240611
DTSTAMP;VALUE=DATE:20240610
UID:2024-06-10/2024-06-11/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补中秋节假期)
DTSTART;VALUE=DATE:20240914
DTEND;VALUE=DATE:20240915
DTSTAMP;VALUE=DATE:20240914
UID:2024-09-14/2024-09-15/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:中秋节假期
DTSTART;VALUE=DATE:20240915
DTEND;VALUE=DATE:20240918
DTSTAMP;VALUE=DATE:20240915
UID:2024-09-15/2024-09-18/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节假期)
DTSTART;VALUE=DATE:20240929
DTEND;VALUE=DATE:20240930
DTSTAMP;VALUE=DATE:20240929
UID:2024-09-29/2024-09-30/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:国庆节假期
DTSTART;VALUE=DATE:20241001
DTEND;VALUE=DATE:20241008
DTSTAMP;VALUE=DATE:20241001
UID:2024-10-01/2024-10-08/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节假期)
DTSTART;VALUE=DATE:20241012
DTEND;VALUE=DATE:20241013
DTSTAMP;VALUE=DATE:20241012
UID:2024-10-12/2024-10-13/NateScarlet/holiday-cn
END:VEVENT
END:VCALENDAR

190
2024.json Normal file
View File

@@ -0,0 +1,190 @@
{
"$schema": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/schema.json",
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2024.json",
"year": 2024,
"papers": [
"https://www.gov.cn/zhengce/zhengceku/202310/content_6911528.htm"
],
"days": [
{
"name": "元旦",
"date": "2024-01-01",
"isOffDay": true
},
{
"name": "春节",
"date": "2024-02-04",
"isOffDay": false
},
{
"name": "春节",
"date": "2024-02-10",
"isOffDay": true
},
{
"name": "春节",
"date": "2024-02-11",
"isOffDay": true
},
{
"name": "春节",
"date": "2024-02-12",
"isOffDay": true
},
{
"name": "春节",
"date": "2024-02-13",
"isOffDay": true
},
{
"name": "春节",
"date": "2024-02-14",
"isOffDay": true
},
{
"name": "春节",
"date": "2024-02-15",
"isOffDay": true
},
{
"name": "春节",
"date": "2024-02-16",
"isOffDay": true
},
{
"name": "春节",
"date": "2024-02-17",
"isOffDay": true
},
{
"name": "春节",
"date": "2024-02-18",
"isOffDay": false
},
{
"name": "清明节",
"date": "2024-04-04",
"isOffDay": true
},
{
"name": "清明节",
"date": "2024-04-05",
"isOffDay": true
},
{
"name": "清明节",
"date": "2024-04-06",
"isOffDay": true
},
{
"name": "清明节",
"date": "2024-04-07",
"isOffDay": false
},
{
"name": "劳动节",
"date": "2024-04-28",
"isOffDay": false
},
{
"name": "劳动节",
"date": "2024-05-01",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2024-05-02",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2024-05-03",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2024-05-04",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2024-05-05",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2024-05-11",
"isOffDay": false
},
{
"name": "端午节",
"date": "2024-06-10",
"isOffDay": true
},
{
"name": "中秋节",
"date": "2024-09-14",
"isOffDay": false
},
{
"name": "中秋节",
"date": "2024-09-15",
"isOffDay": true
},
{
"name": "中秋节",
"date": "2024-09-16",
"isOffDay": true
},
{
"name": "中秋节",
"date": "2024-09-17",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2024-09-29",
"isOffDay": false
},
{
"name": "国庆节",
"date": "2024-10-01",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2024-10-02",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2024-10-03",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2024-10-04",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2024-10-05",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2024-10-06",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2024-10-07",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2024-10-12",
"isOffDay": false
}
]
}

93
2025.ics Normal file
View File

@@ -0,0 +1,93 @@
BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
CLASS:PUBLIC
X-WR-CALDESC:中国法定节假日数据,自动每日抓取国务院公
告。
X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE
TZID:Asia/Shanghai
BEGIN:STANDARD
DTSTART:19700101T000000
TZOFFSETFROM:+0800
TZOFFSETTO:+0800
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
SUMMARY:元旦假期
DTSTART;VALUE=DATE:20250101
DTEND;VALUE=DATE:20250102
DTSTAMP;VALUE=DATE:20250101
UID:2025-01-01/2025-01-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20250126
DTEND;VALUE=DATE:20250127
DTSTAMP;VALUE=DATE:20250126
UID:2025-01-26/2025-01-27/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:春节假期
DTSTART;VALUE=DATE:20250128
DTEND;VALUE=DATE:20250205
DTSTAMP;VALUE=DATE:20250128
UID:2025-01-28/2025-02-05/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20250208
DTEND;VALUE=DATE:20250209
DTSTAMP;VALUE=DATE:20250208
UID:2025-02-08/2025-02-09/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:清明节假期
DTSTART;VALUE=DATE:20250404
DTEND;VALUE=DATE:20250407
DTSTAMP;VALUE=DATE:20250404
UID:2025-04-04/2025-04-07/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补劳动节假期)
DTSTART;VALUE=DATE:20250427
DTEND;VALUE=DATE:20250428
DTSTAMP;VALUE=DATE:20250427
UID:2025-04-27/2025-04-28/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:劳动节假期
DTSTART;VALUE=DATE:20250501
DTEND;VALUE=DATE:20250506
DTSTAMP;VALUE=DATE:20250501
UID:2025-05-01/2025-05-06/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:端午节假期
DTSTART;VALUE=DATE:20250531
DTEND;VALUE=DATE:20250603
DTSTAMP;VALUE=DATE:20250531
UID:2025-05-31/2025-06-03/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节、中秋节假期)
DTSTART;VALUE=DATE:20250928
DTEND;VALUE=DATE:20250929
DTSTAMP;VALUE=DATE:20250928
UID:2025-09-28/2025-09-29/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:国庆节、中秋节假期
DTSTART;VALUE=DATE:20251001
DTEND;VALUE=DATE:20251009
DTSTAMP;VALUE=DATE:20251001
UID:2025-10-01/2025-10-09/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节、中秋节假期)
DTSTART;VALUE=DATE:20251011
DTEND;VALUE=DATE:20251012
DTSTAMP;VALUE=DATE:20251011
UID:2025-10-11/2025-10-12/NateScarlet/holiday-cn
END:VEVENT
END:VCALENDAR

175
2025.json Normal file
View File

@@ -0,0 +1,175 @@
{
"$schema": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/schema.json",
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2025.json",
"year": 2025,
"papers": [
"https://www.gov.cn/zhengce/zhengceku/202411/content_6986383.htm"
],
"days": [
{
"name": "元旦",
"date": "2025-01-01",
"isOffDay": true
},
{
"name": "春节",
"date": "2025-01-26",
"isOffDay": false
},
{
"name": "春节",
"date": "2025-01-28",
"isOffDay": true
},
{
"name": "春节",
"date": "2025-01-29",
"isOffDay": true
},
{
"name": "春节",
"date": "2025-01-30",
"isOffDay": true
},
{
"name": "春节",
"date": "2025-01-31",
"isOffDay": true
},
{
"name": "春节",
"date": "2025-02-01",
"isOffDay": true
},
{
"name": "春节",
"date": "2025-02-02",
"isOffDay": true
},
{
"name": "春节",
"date": "2025-02-03",
"isOffDay": true
},
{
"name": "春节",
"date": "2025-02-04",
"isOffDay": true
},
{
"name": "春节",
"date": "2025-02-08",
"isOffDay": false
},
{
"name": "清明节",
"date": "2025-04-04",
"isOffDay": true
},
{
"name": "清明节",
"date": "2025-04-05",
"isOffDay": true
},
{
"name": "清明节",
"date": "2025-04-06",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2025-04-27",
"isOffDay": false
},
{
"name": "劳动节",
"date": "2025-05-01",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2025-05-02",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2025-05-03",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2025-05-04",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2025-05-05",
"isOffDay": true
},
{
"name": "端午节",
"date": "2025-05-31",
"isOffDay": true
},
{
"name": "端午节",
"date": "2025-06-01",
"isOffDay": true
},
{
"name": "端午节",
"date": "2025-06-02",
"isOffDay": true
},
{
"name": "国庆节、中秋节",
"date": "2025-09-28",
"isOffDay": false
},
{
"name": "国庆节、中秋节",
"date": "2025-10-01",
"isOffDay": true
},
{
"name": "国庆节、中秋节",
"date": "2025-10-02",
"isOffDay": true
},
{
"name": "国庆节、中秋节",
"date": "2025-10-03",
"isOffDay": true
},
{
"name": "国庆节、中秋节",
"date": "2025-10-04",
"isOffDay": true
},
{
"name": "国庆节、中秋节",
"date": "2025-10-05",
"isOffDay": true
},
{
"name": "国庆节、中秋节",
"date": "2025-10-06",
"isOffDay": true
},
{
"name": "国庆节、中秋节",
"date": "2025-10-07",
"isOffDay": true
},
{
"name": "国庆节、中秋节",
"date": "2025-10-08",
"isOffDay": true
},
{
"name": "国庆节、中秋节",
"date": "2025-10-11",
"isOffDay": false
}
]
}

107
2026.ics Normal file
View File

@@ -0,0 +1,107 @@
BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
CLASS:PUBLIC
X-WR-CALDESC:中国法定节假日数据,自动每日抓取国务院公
告。
X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE
TZID:Asia/Shanghai
BEGIN:STANDARD
DTSTART:19700101T000000
TZOFFSETFROM:+0800
TZOFFSETTO:+0800
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
SUMMARY:元旦假期
DTSTART;VALUE=DATE:20260101
DTEND;VALUE=DATE:20260104
DTSTAMP;VALUE=DATE:20260101
UID:2026-01-01/2026-01-04/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补元旦假期)
DTSTART;VALUE=DATE:20260104
DTEND;VALUE=DATE:20260105
DTSTAMP;VALUE=DATE:20260104
UID:2026-01-04/2026-01-05/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20260214
DTEND;VALUE=DATE:20260215
DTSTAMP;VALUE=DATE:20260214
UID:2026-02-14/2026-02-15/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:春节假期
DTSTART;VALUE=DATE:20260215
DTEND;VALUE=DATE:20260224
DTSTAMP;VALUE=DATE:20260215
UID:2026-02-15/2026-02-24/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20260228
DTEND;VALUE=DATE:20260301
DTSTAMP;VALUE=DATE:20260228
UID:2026-02-28/2026-03-01/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:清明节假期
DTSTART;VALUE=DATE:20260404
DTEND;VALUE=DATE:20260407
DTSTAMP;VALUE=DATE:20260404
UID:2026-04-04/2026-04-07/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:劳动节假期
DTSTART;VALUE=DATE:20260501
DTEND;VALUE=DATE:20260506
DTSTAMP;VALUE=DATE:20260501
UID:2026-05-01/2026-05-06/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补劳动节假期)
DTSTART;VALUE=DATE:20260509
DTEND;VALUE=DATE:20260510
DTSTAMP;VALUE=DATE:20260509
UID:2026-05-09/2026-05-10/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:端午节假期
DTSTART;VALUE=DATE:20260619
DTEND;VALUE=DATE:20260622
DTSTAMP;VALUE=DATE:20260619
UID:2026-06-19/2026-06-22/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节假期)
DTSTART;VALUE=DATE:20260920
DTEND;VALUE=DATE:20260921
DTSTAMP;VALUE=DATE:20260920
UID:2026-09-20/2026-09-21/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:中秋节假期
DTSTART;VALUE=DATE:20260925
DTEND;VALUE=DATE:20260928
DTSTAMP;VALUE=DATE:20260925
UID:2026-09-25/2026-09-28/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:国庆节假期
DTSTART;VALUE=DATE:20261001
DTEND;VALUE=DATE:20261008
DTSTAMP;VALUE=DATE:20261001
UID:2026-10-01/2026-10-08/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节假期)
DTSTART;VALUE=DATE:20261010
DTEND;VALUE=DATE:20261011
DTSTAMP;VALUE=DATE:20261010
UID:2026-10-10/2026-10-11/NateScarlet/holiday-cn
END:VEVENT
END:VCALENDAR

205
2026.json Normal file
View File

@@ -0,0 +1,205 @@
{
"$schema": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/schema.json",
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2026.json",
"year": 2026,
"papers": [
"https://www.gov.cn/zhengce/zhengceku/202511/content_7047091.htm"
],
"days": [
{
"name": "元旦",
"date": "2026-01-01",
"isOffDay": true
},
{
"name": "元旦",
"date": "2026-01-02",
"isOffDay": true
},
{
"name": "元旦",
"date": "2026-01-03",
"isOffDay": true
},
{
"name": "元旦",
"date": "2026-01-04",
"isOffDay": false
},
{
"name": "春节",
"date": "2026-02-14",
"isOffDay": false
},
{
"name": "春节",
"date": "2026-02-15",
"isOffDay": true
},
{
"name": "春节",
"date": "2026-02-16",
"isOffDay": true
},
{
"name": "春节",
"date": "2026-02-17",
"isOffDay": true
},
{
"name": "春节",
"date": "2026-02-18",
"isOffDay": true
},
{
"name": "春节",
"date": "2026-02-19",
"isOffDay": true
},
{
"name": "春节",
"date": "2026-02-20",
"isOffDay": true
},
{
"name": "春节",
"date": "2026-02-21",
"isOffDay": true
},
{
"name": "春节",
"date": "2026-02-22",
"isOffDay": true
},
{
"name": "春节",
"date": "2026-02-23",
"isOffDay": true
},
{
"name": "春节",
"date": "2026-02-28",
"isOffDay": false
},
{
"name": "清明节",
"date": "2026-04-04",
"isOffDay": true
},
{
"name": "清明节",
"date": "2026-04-05",
"isOffDay": true
},
{
"name": "清明节",
"date": "2026-04-06",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2026-05-01",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2026-05-02",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2026-05-03",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2026-05-04",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2026-05-05",
"isOffDay": true
},
{
"name": "劳动节",
"date": "2026-05-09",
"isOffDay": false
},
{
"name": "端午节",
"date": "2026-06-19",
"isOffDay": true
},
{
"name": "端午节",
"date": "2026-06-20",
"isOffDay": true
},
{
"name": "端午节",
"date": "2026-06-21",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2026-09-20",
"isOffDay": false
},
{
"name": "中秋节",
"date": "2026-09-25",
"isOffDay": true
},
{
"name": "中秋节",
"date": "2026-09-26",
"isOffDay": true
},
{
"name": "中秋节",
"date": "2026-09-27",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2026-10-01",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2026-10-02",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2026-10-03",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2026-10-04",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2026-10-05",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2026-10-06",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2026-10-07",
"isOffDay": true
},
{
"name": "国庆节",
"date": "2026-10-10",
"isOffDay": false
}
]
}

16
2027.ics Normal file
View File

@@ -0,0 +1,16 @@
BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
CLASS:PUBLIC
X-WR-CALDESC:中国法定节假日数据,自动每日抓取国务院公
告。
X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE
TZID:Asia/Shanghai
BEGIN:STANDARD
DTSTART:19700101T000000
TZOFFSETFROM:+0800
TZOFFSETTO:+0800
END:STANDARD
END:VTIMEZONE
END:VCALENDAR

7
2027.json Normal file
View File

@@ -0,0 +1,7 @@
{
"$schema": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/schema.json",
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/2027.json",
"year": 2027,
"papers": [],
"days": []
}

View File

@@ -3,13 +3,17 @@
default: format default: format
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
PYTHON?=py -3.8 PYTHON?=py -3.12
else else
PYTHON?=python3 PYTHON?=python3
endif endif
lint: lint:
$(PYTHON) -m black -t py38 --check --diff . $(PYTHON) -m black -t py312 --check --diff .
format: format:
$(PYTHON) -m black -t py38 . $(PYTHON) -m black -t py312 .
.PHONY: test
test:
$(PYTHON) -m pytest

138
README.md
View File

@@ -3,18 +3,20 @@
[![Build Status](https://github.com/NateScarlet/holiday-cn/workflows/CI/badge.svg)](https://github.com/NateScarlet/holiday-cn/actions) [![Build Status](https://github.com/NateScarlet/holiday-cn/workflows/CI/badge.svg)](https://github.com/NateScarlet/holiday-cn/actions)
[![Release](https://img.shields.io/github/release/NateScarlet/holiday-cn.svg)](https://github.com/NateScarlet/holiday-cn/releases/latest) [![Release](https://img.shields.io/github/release/NateScarlet/holiday-cn.svg)](https://github.com/NateScarlet/holiday-cn/releases/latest)
[![CalVer](https://img.shields.io/badge/calver-YYYY.0M.0D-22bfda.svg)](http://calver.org) [![CalVer](https://img.shields.io/badge/calver-YYYY.0M.0D-22bfda.svg)](http://calver.org)
[![Maintainability](https://api.codeclimate.com/v1/badges/c8e9d9c51bd2d858c577/maintainability)](https://codeclimate.com/github/NateScarlet/holiday-cn/maintainability) [![JSDelivr](https://data.jsdelivr.com/v1/package/gh/NateScarlet/holiday-cn/badge?style=rounded)](https://www.jsdelivr.com/package/gh/NateScarlet/holiday-cn)
[![Test Coverage](https://api.codeclimate.com/v1/badges/c8e9d9c51bd2d858c577/test_coverage)](https://codeclimate.com/github/NateScarlet/holiday-cn/test_coverage) ![Maintenance](https://img.shields.io/maintenance/yes/2024.svg)
![Maintenance](https://img.shields.io/maintenance/yes/2022.svg)
中国法定节假日数据 自动每日抓取国务院公告 中国大陆及香港节假日数据
- 中国大陆:自动每日抓取国务院公告
- 香港:来源于香港特别行政区政府 [1823.gov.hk](https://www.1823.gov.hk/common/ical/tc.json),数据覆盖 2024 年起
- [x] 提供 JSON 格式节假日数据 - [x] 提供 JSON 格式节假日数据
- [x] CI 自动更新 - [x] CI 自动更新
- [x] 数据变化时自动发布新版本 ( `Watch` - `Release only` 以获取邮件提醒! ) - [x] 数据变化时自动发布新版本 ( `Watch` - `Release only` 以获取邮件提醒! )
- [x] [发布页面]提供 JSON 打包下载 - [x] [发布页面]提供 JSON 打包下载
数据格式: 数据格式(中国大陆、香港通用):
[JSON Schema](./schema.json) [JSON Schema](./schema.json)
@@ -22,7 +24,7 @@
interface Holidays { interface Holidays {
/** 完整年份, 整数。*/ /** 完整年份, 整数。*/
year: number; year: number;
/** 所用国务院文件网址列表 */ /** 所用数据来源网址列表 */
papers: string[]; papers: string[];
days: { days: {
/** 节日名称 */ /** 节日名称 */
@@ -37,13 +39,23 @@ interface Holidays {
## 注意事项 ## 注意事项
**中国大陆**
- 年份是按照国务院文件标题年份而不是日期年份12 月份的日期可能会被下一年的文件影响,因此应检查两个文件。 - 年份是按照国务院文件标题年份而不是日期年份12 月份的日期可能会被下一年的文件影响,因此应检查两个文件。
- `与周末连休` 的周末不是法定节假日,数据里不会包含,见[《全国年节及纪念日放假办法》](https://www.gov.cn/zhengce/content/202411/content_6986380.htm) [#213](https://github.com/NateScarlet/holiday-cn/issues/213#issuecomment-1869546011) [#221](https://github.com/NateScarlet/holiday-cn/issues/221)
**香港**
- 香港不设调休补班制度,数据中不会出现 `isOffDay: false` 的条目。
- 假期名称为繁体中文。
- 数据覆盖范围取决于港府发布进度,通常提前公布至次年。
## 通过互联网使用 ## 通过互联网使用
提示:任何第三方服务都可能故障或停止服务,如果稳定性要求高请自己搭建静态文件服务。 提示:任何第三方服务都可能故障或停止服务,如果稳定性要求高请自己搭建静态文件服务。
数据地址格式: ### 中国大陆
`https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/{年份}.json` `https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/{年份}.json`
@@ -51,26 +63,134 @@ interface Holidays {
`https://cdn.jsdelivr.net/gh/NateScarlet/holiday-cn@master/{年份}.json` `https://cdn.jsdelivr.net/gh/NateScarlet/holiday-cn@master/{年份}.json`
`https://fastly.jsdelivr.net/gh/NateScarlet/holiday-cn@master/{年份}.json`
也可尝试使用 [ghproxy](https://github.com/hunshcn/gh-proxy) 或其他 Github 加速: 也可尝试使用 [ghproxy](https://github.com/hunshcn/gh-proxy) 或其他 Github 加速:
`https://ghproxy.com/https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/{年份}.json` `https://{ghproxy服务}/https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/{年份}.json`
~~访问 github 不方便时可使用国内镜像仓库~~ 2022-08-05: coding 现在要求登录才能下载开源仓库的文件。 ~~访问 github 不方便时可使用国内镜像仓库~~ 2022-08-05: coding 现在要求登录才能下载开源仓库的文件。
~~`https://natescarlet.coding.net/p/github/d/holiday-cn/git/raw/master/{年份}.json`~~ ~~`https://natescarlet.coding.net/p/github/d/holiday-cn/git/raw/master/{年份}.json`~~
### 香港
`https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/hk/{年份}.json`
## ICalendar 订阅 ## ICalendar 订阅
网址格式参见上一节 ### 中国大陆
`{年份}.ics` 为对应年份的节假日 `{年份}.ics` 为对应年份的节假日
`holiday-cn.ics` 为 3 年前至次年的节假日 `holiday-cn.ics` 为 3 年前至次年的节假日
### 香港
`hk/{年份}.ics` 为对应年份的节假日
`holiday-hk.ics` 为 3 年前至次年的节假日
感谢 @retanoj 的 ics 格式转换实现 感谢 @retanoj 的 ics 格式转换实现
## 作为 git 子模块使用 ## 作为 git 子模块使用
参见 [Git 工具 - 子模块](https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97) 参见 [Git 工具 - 子模块](https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97)
## 数据生成
安装依赖:
```sh
pip install -r dev-requirements.txt
```
更新当年及次年数据(所有地区):
```sh
python scripts/update.py
```
只更新指定地区:
```sh
python scripts/update.py --region cn # 仅中国大陆
python scripts/update.py --region hk # 仅香港
```
更新所有历史年份(仅中国大陆,香港数据源仅覆盖 2024 年起):
```sh
python scripts/update.py --all --region cn
```
CI 每日自动执行 `python scripts/update.py --release`,数据有变化时自动提交并发布新版本。
## 导入到业务系统teramesh-backend
数据通过 Django management command 导入工作日历:
```sh
# 进入应用容器
kubectl exec -it pod/teramesh-app-0 -- /bin/sh
# 导入所有地区(中国大陆 + 香港)
python manage.py populate_working_calendar
# 只导入指定地区
python manage.py populate_working_calendar --region CN
python manage.py populate_working_calendar --region HK
```
命令会导入当年及次年的假期数据。数据按 `country` 级别写入,部署在香港(`country=HK`)的站点自动使用香港假期,内地站点使用内地假期,无需额外配置。
## 扩展支持新地区
如需接入其他地区(如美国、日本等),按以下步骤操作:
**1. 新增数据抓取模块**
`scripts/` 下新建 `fetch_{地区代码}.py`,实现 `fetch_{地区代码}_holiday(year: int) -> dict`,返回格式与现有地区一致:
```python
{
"year": 2025,
"papers": ["数据来源URL"],
"days": [
{"name": "假期名称", "date": "2025-01-01", "isOffDay": True}
]
}
```
注意:若该地区无调休补班制度,`isOffDay` 始终为 `True`
**2. 在 `scripts/update.py` 的 `REGIONS` 中注册**
```python
REGIONS = {
"cn": { ... },
"hk": { ... },
"us": { # 新增
"fetch": fetch_us_holiday,
"start_year": 2024,
"subdir": "us",
"main_ics_name": "holiday-us.ics",
"cal_name": "美国联邦假期",
"cal_desc": "美国联邦公共假期数据。",
},
}
```
**3. 在 `teramesh-backend` 的 `HOLIDAY_SOURCES` 中注册**
```python
HOLIDAY_SOURCES = {
"CN": f"{GITEA_BASE}/{{year}}.json",
"HK": f"{GITEA_BASE}/hk/{{year}}.json",
"US": f"{GITEA_BASE}/us/{{year}}.json", # 新增
}
```
之后运行 `python manage.py populate_working_calendar --region US` 即可导入,其余地区不受影响。
[发布页面]: https://github.com/NateScarlet/holiday-cn/releases [发布页面]: https://github.com/NateScarlet/holiday-cn/releases

View File

@@ -1,3 +1,10 @@
pytest==7.2.0 # main
coverage==6.5.0 requests==2.32.3
black==22.10.0 beautifulsoup4==4.12.3
tqdm==4.67.1
icalendar==6.1.0
# test
pytest==8.3.4
coverage==7.6.9
black==24.10.0

100
hk/2026.ics Normal file
View File

@@ -0,0 +1,100 @@
BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
CLASS:PUBLIC
X-WR-CALDESC:香港公众假期数据,来源:香港特别行政区政
府 1823.gov.hk。
X-WR-CALNAME:香港公众假期
BEGIN:VTIMEZONE
TZID:Asia/Shanghai
BEGIN:STANDARD
DTSTART:19700101T000000
TZOFFSETFROM:+0800
TZOFFSETTO:+0800
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
SUMMARY:一月一日假期
DTSTART;VALUE=DATE:20260101
DTEND;VALUE=DATE:20260102
DTSTAMP;VALUE=DATE:20260101
UID:2026-01-01/2026-01-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:農曆年初一假期
DTSTART;VALUE=DATE:20260217
DTEND;VALUE=DATE:20260220
DTSTAMP;VALUE=DATE:20260217
UID:2026-02-17/2026-02-20/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:耶穌受難節假期
DTSTART;VALUE=DATE:20260403
DTEND;VALUE=DATE:20260405
DTSTAMP;VALUE=DATE:20260403
UID:2026-04-03/2026-04-05/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:清明節翌日假期
DTSTART;VALUE=DATE:20260406
DTEND;VALUE=DATE:20260408
DTSTAMP;VALUE=DATE:20260406
UID:2026-04-06/2026-04-08/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:勞動節假期
DTSTART;VALUE=DATE:20260501
DTEND;VALUE=DATE:20260502
DTSTAMP;VALUE=DATE:20260501
UID:2026-05-01/2026-05-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:佛誕翌日假期
DTSTART;VALUE=DATE:20260525
DTEND;VALUE=DATE:20260526
DTSTAMP;VALUE=DATE:20260525
UID:2026-05-25/2026-05-26/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:端午節假期
DTSTART;VALUE=DATE:20260619
DTEND;VALUE=DATE:20260620
DTSTAMP;VALUE=DATE:20260619
UID:2026-06-19/2026-06-20/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:香港特別行政區成立紀念日假期
DTSTART;VALUE=DATE:20260701
DTEND;VALUE=DATE:20260702
DTSTAMP;VALUE=DATE:20260701
UID:2026-07-01/2026-07-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:中秋節翌日假期
DTSTART;VALUE=DATE:20260926
DTEND;VALUE=DATE:20260927
DTSTAMP;VALUE=DATE:20260926
UID:2026-09-26/2026-09-27/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:國慶日假期
DTSTART;VALUE=DATE:20261001
DTEND;VALUE=DATE:20261002
DTSTAMP;VALUE=DATE:20261001
UID:2026-10-01/2026-10-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:重陽節翌日假期
DTSTART;VALUE=DATE:20261019
DTEND;VALUE=DATE:20261020
DTSTAMP;VALUE=DATE:20261019
UID:2026-10-19/2026-10-20/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:聖誕節假期
DTSTART;VALUE=DATE:20261225
DTEND;VALUE=DATE:20261227
DTSTAMP;VALUE=DATE:20261225
UID:2026-12-25/2026-12-27/NateScarlet/holiday-cn
END:VEVENT
END:VCALENDAR

95
hk/2026.json Normal file
View File

@@ -0,0 +1,95 @@
{
"$schema": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/schema.json",
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/hk/2026.json",
"year": 2026,
"papers": [
"https://www.1823.gov.hk/common/ical/tc.json"
],
"days": [
{
"name": "一月一日",
"date": "2026-01-01",
"isOffDay": true
},
{
"name": "農曆年初一",
"date": "2026-02-17",
"isOffDay": true
},
{
"name": "農曆年初二",
"date": "2026-02-18",
"isOffDay": true
},
{
"name": "農曆年初三",
"date": "2026-02-19",
"isOffDay": true
},
{
"name": "耶穌受難節",
"date": "2026-04-03",
"isOffDay": true
},
{
"name": "耶穌受難節翌日",
"date": "2026-04-04",
"isOffDay": true
},
{
"name": "清明節翌日",
"date": "2026-04-06",
"isOffDay": true
},
{
"name": "復活節星期一翌日",
"date": "2026-04-07",
"isOffDay": true
},
{
"name": "勞動節",
"date": "2026-05-01",
"isOffDay": true
},
{
"name": "佛誕翌日",
"date": "2026-05-25",
"isOffDay": true
},
{
"name": "端午節",
"date": "2026-06-19",
"isOffDay": true
},
{
"name": "香港特別行政區成立紀念日",
"date": "2026-07-01",
"isOffDay": true
},
{
"name": "中秋節翌日",
"date": "2026-09-26",
"isOffDay": true
},
{
"name": "國慶日",
"date": "2026-10-01",
"isOffDay": true
},
{
"name": "重陽節翌日",
"date": "2026-10-19",
"isOffDay": true
},
{
"name": "聖誕節",
"date": "2026-12-25",
"isOffDay": true
},
{
"name": "聖誕節後第一個周日",
"date": "2026-12-26",
"isOffDay": true
}
]
}

16
hk/2027.ics Normal file
View File

@@ -0,0 +1,16 @@
BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
CLASS:PUBLIC
X-WR-CALDESC:香港公众假期数据,来源:香港特别行政区政
府 1823.gov.hk。
X-WR-CALNAME:香港公众假期
BEGIN:VTIMEZONE
TZID:Asia/Shanghai
BEGIN:STANDARD
DTSTART:19700101T000000
TZOFFSETFROM:+0800
TZOFFSETTO:+0800
END:STANDARD
END:VTIMEZONE
END:VCALENDAR

9
hk/2027.json Normal file
View File

@@ -0,0 +1,9 @@
{
"$schema": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/schema.json",
"$id": "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/hk/2027.json",
"year": 2027,
"papers": [
"https://www.1823.gov.hk/common/ical/tc.json"
],
"days": []
}

View File

@@ -8,377 +8,13 @@ X-WR-CALNAME:中国法定节假日
BEGIN:VTIMEZONE BEGIN:VTIMEZONE
TZID:Asia/Shanghai TZID:Asia/Shanghai
BEGIN:STANDARD BEGIN:STANDARD
DTSTART;VALUE=DATE-TIME:19700101T000000 DTSTART:19700101T000000
TZOFFSETFROM:+0800 TZOFFSETFROM:+0800
TZOFFSETTO:+0800 TZOFFSETTO:+0800
END:STANDARD END:STANDARD
END:VTIMEZONE END:VTIMEZONE
BEGIN:VEVENT BEGIN:VEVENT
SUMMARY:元旦假期 SUMMARY:元旦假期
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
DTSTAMP;VALUE=DATE:20180101
UID:2018-01-01/2018-01-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20180211
DTEND;VALUE=DATE:20180212
DTSTAMP;VALUE=DATE:20180211
UID:2018-02-11/2018-02-12/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:春节假期
DTSTART;VALUE=DATE:20180215
DTEND;VALUE=DATE:20180222
DTSTAMP;VALUE=DATE:20180215
UID:2018-02-15/2018-02-22/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20180224
DTEND;VALUE=DATE:20180225
DTSTAMP;VALUE=DATE:20180224
UID:2018-02-24/2018-02-25/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:清明节假期
DTSTART;VALUE=DATE:20180405
DTEND;VALUE=DATE:20180408
DTSTAMP;VALUE=DATE:20180405
UID:2018-04-05/2018-04-08/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补清明节假期)
DTSTART;VALUE=DATE:20180408
DTEND;VALUE=DATE:20180409
DTSTAMP;VALUE=DATE:20180408
UID:2018-04-08/2018-04-09/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补劳动节假期)
DTSTART;VALUE=DATE:20180428
DTEND;VALUE=DATE:20180429
DTSTAMP;VALUE=DATE:20180428
UID:2018-04-28/2018-04-29/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:劳动节假期
DTSTART;VALUE=DATE:20180429
DTEND;VALUE=DATE:20180502
DTSTAMP;VALUE=DATE:20180429
UID:2018-04-29/2018-05-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:端午节假期
DTSTART;VALUE=DATE:20180618
DTEND;VALUE=DATE:20180619
DTSTAMP;VALUE=DATE:20180618
UID:2018-06-18/2018-06-19/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:中秋节假期
DTSTART;VALUE=DATE:20180924
DTEND;VALUE=DATE:20180925
DTSTAMP;VALUE=DATE:20180924
UID:2018-09-24/2018-09-25/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节假期)
DTSTART;VALUE=DATE:20180929
DTEND;VALUE=DATE:20181001
DTSTAMP;VALUE=DATE:20180929
UID:2018-09-29/2018-10-01/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:国庆节假期
DTSTART;VALUE=DATE:20181001
DTEND;VALUE=DATE:20181008
DTSTAMP;VALUE=DATE:20181001
UID:2018-10-01/2018-10-08/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补元旦假期)
DTSTART;VALUE=DATE:20181229
DTEND;VALUE=DATE:20181230
DTSTAMP;VALUE=DATE:20181229
UID:2018-12-29/2018-12-30/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:元旦假期
DTSTART;VALUE=DATE:20181230
DTEND;VALUE=DATE:20190102
DTSTAMP;VALUE=DATE:20181230
UID:2018-12-30/2019-01-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20190202
DTEND;VALUE=DATE:20190204
DTSTAMP;VALUE=DATE:20190202
UID:2019-02-02/2019-02-04/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:春节假期
DTSTART;VALUE=DATE:20190204
DTEND;VALUE=DATE:20190211
DTSTAMP;VALUE=DATE:20190204
UID:2019-02-04/2019-02-11/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:清明节假期
DTSTART;VALUE=DATE:20190405
DTEND;VALUE=DATE:20190406
DTSTAMP;VALUE=DATE:20190405
UID:2019-04-05/2019-04-06/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补劳动节假期)
DTSTART;VALUE=DATE:20190428
DTEND;VALUE=DATE:20190429
DTSTAMP;VALUE=DATE:20190428
UID:2019-04-28/2019-04-29/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:劳动节假期
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190505
DTSTAMP;VALUE=DATE:20190501
UID:2019-05-01/2019-05-05/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补劳动节假期)
DTSTART;VALUE=DATE:20190505
DTEND;VALUE=DATE:20190506
DTSTAMP;VALUE=DATE:20190505
UID:2019-05-05/2019-05-06/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:端午节假期
DTSTART;VALUE=DATE:20190607
DTEND;VALUE=DATE:20190608
DTSTAMP;VALUE=DATE:20190607
UID:2019-06-07/2019-06-08/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:中秋节假期
DTSTART;VALUE=DATE:20190913
DTEND;VALUE=DATE:20190914
DTSTAMP;VALUE=DATE:20190913
UID:2019-09-13/2019-09-14/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节假期)
DTSTART;VALUE=DATE:20190929
DTEND;VALUE=DATE:20190930
DTSTAMP;VALUE=DATE:20190929
UID:2019-09-29/2019-09-30/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:国庆节假期
DTSTART;VALUE=DATE:20191001
DTEND;VALUE=DATE:20191008
DTSTAMP;VALUE=DATE:20191001
UID:2019-10-01/2019-10-08/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节假期)
DTSTART;VALUE=DATE:20191012
DTEND;VALUE=DATE:20191013
DTSTAMP;VALUE=DATE:20191012
UID:2019-10-12/2019-10-13/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:元旦假期
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
DTSTAMP;VALUE=DATE:20200101
UID:2020-01-01/2020-01-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20200119
DTEND;VALUE=DATE:20200120
DTSTAMP;VALUE=DATE:20200119
UID:2020-01-19/2020-01-20/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:春节假期
DTSTART;VALUE=DATE:20200124
DTEND;VALUE=DATE:20200203
DTSTAMP;VALUE=DATE:20200124
UID:2020-01-24/2020-02-03/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20200203
DTEND;VALUE=DATE:20200204
DTSTAMP;VALUE=DATE:20200203
UID:2020-02-03/2020-02-04/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:清明节假期
DTSTART;VALUE=DATE:20200404
DTEND;VALUE=DATE:20200407
DTSTAMP;VALUE=DATE:20200404
UID:2020-04-04/2020-04-07/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补劳动节假期)
DTSTART;VALUE=DATE:20200426
DTEND;VALUE=DATE:20200427
DTSTAMP;VALUE=DATE:20200426
UID:2020-04-26/2020-04-27/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:劳动节假期
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200506
DTSTAMP;VALUE=DATE:20200501
UID:2020-05-01/2020-05-06/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补劳动节假期)
DTSTART;VALUE=DATE:20200509
DTEND;VALUE=DATE:20200510
DTSTAMP;VALUE=DATE:20200509
UID:2020-05-09/2020-05-10/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:端午节假期
DTSTART;VALUE=DATE:20200625
DTEND;VALUE=DATE:20200628
DTSTAMP;VALUE=DATE:20200625
UID:2020-06-25/2020-06-28/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补端午节假期)
DTSTART;VALUE=DATE:20200628
DTEND;VALUE=DATE:20200629
DTSTAMP;VALUE=DATE:20200628
UID:2020-06-28/2020-06-29/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节、中秋节假期)
DTSTART;VALUE=DATE:20200927
DTEND;VALUE=DATE:20200928
DTSTAMP;VALUE=DATE:20200927
UID:2020-09-27/2020-09-28/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:国庆节、中秋节假期
DTSTART;VALUE=DATE:20201001
DTEND;VALUE=DATE:20201009
DTSTAMP;VALUE=DATE:20201001
UID:2020-10-01/2020-10-09/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节、中秋节假期)
DTSTART;VALUE=DATE:20201010
DTEND;VALUE=DATE:20201011
DTSTAMP;VALUE=DATE:20201010
UID:2020-10-10/2020-10-11/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:元旦假期
DTSTART;VALUE=DATE:20210101
DTEND;VALUE=DATE:20210104
DTSTAMP;VALUE=DATE:20210101
UID:2021-01-01/2021-01-04/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20210207
DTEND;VALUE=DATE:20210208
DTSTAMP;VALUE=DATE:20210207
UID:2021-02-07/2021-02-08/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:春节假期
DTSTART;VALUE=DATE:20210211
DTEND;VALUE=DATE:20210218
DTSTAMP;VALUE=DATE:20210211
UID:2021-02-11/2021-02-18/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20210220
DTEND;VALUE=DATE:20210221
DTSTAMP;VALUE=DATE:20210220
UID:2021-02-20/2021-02-21/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:清明节假期
DTSTART;VALUE=DATE:20210403
DTEND;VALUE=DATE:20210406
DTSTAMP;VALUE=DATE:20210403
UID:2021-04-03/2021-04-06/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补劳动节假期)
DTSTART;VALUE=DATE:20210425
DTEND;VALUE=DATE:20210426
DTSTAMP;VALUE=DATE:20210425
UID:2021-04-25/2021-04-26/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:劳动节假期
DTSTART;VALUE=DATE:20210501
DTEND;VALUE=DATE:20210506
DTSTAMP;VALUE=DATE:20210501
UID:2021-05-01/2021-05-06/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补劳动节假期)
DTSTART;VALUE=DATE:20210508
DTEND;VALUE=DATE:20210509
DTSTAMP;VALUE=DATE:20210508
UID:2021-05-08/2021-05-09/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:端午节假期
DTSTART;VALUE=DATE:20210612
DTEND;VALUE=DATE:20210615
DTSTAMP;VALUE=DATE:20210612
UID:2021-06-12/2021-06-15/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补中秋节假期)
DTSTART;VALUE=DATE:20210918
DTEND;VALUE=DATE:20210919
DTSTAMP;VALUE=DATE:20210918
UID:2021-09-18/2021-09-19/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:中秋节假期
DTSTART;VALUE=DATE:20210919
DTEND;VALUE=DATE:20210922
DTSTAMP;VALUE=DATE:20210919
UID:2021-09-19/2021-09-22/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节假期)
DTSTART;VALUE=DATE:20210926
DTEND;VALUE=DATE:20210927
DTSTAMP;VALUE=DATE:20210926
UID:2021-09-26/2021-09-27/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:国庆节假期
DTSTART;VALUE=DATE:20211001
DTEND;VALUE=DATE:20211008
DTSTAMP;VALUE=DATE:20211001
UID:2021-10-01/2021-10-08/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节假期)
DTSTART;VALUE=DATE:20211009
DTEND;VALUE=DATE:20211010
DTSTAMP;VALUE=DATE:20211009
UID:2021-10-09/2021-10-10/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:元旦假期
DTSTART;VALUE=DATE:20220101 DTSTART;VALUE=DATE:20220101
DTEND;VALUE=DATE:20220104 DTEND;VALUE=DATE:20220104
DTSTAMP;VALUE=DATE:20220101 DTSTAMP;VALUE=DATE:20220101
@@ -538,4 +174,277 @@ DTEND;VALUE=DATE:20231009
DTSTAMP;VALUE=DATE:20231007 DTSTAMP;VALUE=DATE:20231007
UID:2023-10-07/2023-10-09/NateScarlet/holiday-cn UID:2023-10-07/2023-10-09/NateScarlet/holiday-cn
END:VEVENT END:VEVENT
BEGIN:VEVENT
SUMMARY:元旦假期
DTSTART;VALUE=DATE:20240101
DTEND;VALUE=DATE:20240102
DTSTAMP;VALUE=DATE:20240101
UID:2024-01-01/2024-01-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20240204
DTEND;VALUE=DATE:20240205
DTSTAMP;VALUE=DATE:20240204
UID:2024-02-04/2024-02-05/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:春节假期
DTSTART;VALUE=DATE:20240210
DTEND;VALUE=DATE:20240218
DTSTAMP;VALUE=DATE:20240210
UID:2024-02-10/2024-02-18/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20240218
DTEND;VALUE=DATE:20240219
DTSTAMP;VALUE=DATE:20240218
UID:2024-02-18/2024-02-19/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:清明节假期
DTSTART;VALUE=DATE:20240404
DTEND;VALUE=DATE:20240407
DTSTAMP;VALUE=DATE:20240404
UID:2024-04-04/2024-04-07/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补清明节假期)
DTSTART;VALUE=DATE:20240407
DTEND;VALUE=DATE:20240408
DTSTAMP;VALUE=DATE:20240407
UID:2024-04-07/2024-04-08/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补劳动节假期)
DTSTART;VALUE=DATE:20240428
DTEND;VALUE=DATE:20240429
DTSTAMP;VALUE=DATE:20240428
UID:2024-04-28/2024-04-29/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:劳动节假期
DTSTART;VALUE=DATE:20240501
DTEND;VALUE=DATE:20240506
DTSTAMP;VALUE=DATE:20240501
UID:2024-05-01/2024-05-06/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补劳动节假期)
DTSTART;VALUE=DATE:20240511
DTEND;VALUE=DATE:20240512
DTSTAMP;VALUE=DATE:20240511
UID:2024-05-11/2024-05-12/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:端午节假期
DTSTART;VALUE=DATE:20240610
DTEND;VALUE=DATE:20240611
DTSTAMP;VALUE=DATE:20240610
UID:2024-06-10/2024-06-11/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补中秋节假期)
DTSTART;VALUE=DATE:20240914
DTEND;VALUE=DATE:20240915
DTSTAMP;VALUE=DATE:20240914
UID:2024-09-14/2024-09-15/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:中秋节假期
DTSTART;VALUE=DATE:20240915
DTEND;VALUE=DATE:20240918
DTSTAMP;VALUE=DATE:20240915
UID:2024-09-15/2024-09-18/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节假期)
DTSTART;VALUE=DATE:20240929
DTEND;VALUE=DATE:20240930
DTSTAMP;VALUE=DATE:20240929
UID:2024-09-29/2024-09-30/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:国庆节假期
DTSTART;VALUE=DATE:20241001
DTEND;VALUE=DATE:20241008
DTSTAMP;VALUE=DATE:20241001
UID:2024-10-01/2024-10-08/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节假期)
DTSTART;VALUE=DATE:20241012
DTEND;VALUE=DATE:20241013
DTSTAMP;VALUE=DATE:20241012
UID:2024-10-12/2024-10-13/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:元旦假期
DTSTART;VALUE=DATE:20250101
DTEND;VALUE=DATE:20250102
DTSTAMP;VALUE=DATE:20250101
UID:2025-01-01/2025-01-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20250126
DTEND;VALUE=DATE:20250127
DTSTAMP;VALUE=DATE:20250126
UID:2025-01-26/2025-01-27/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:春节假期
DTSTART;VALUE=DATE:20250128
DTEND;VALUE=DATE:20250205
DTSTAMP;VALUE=DATE:20250128
UID:2025-01-28/2025-02-05/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20250208
DTEND;VALUE=DATE:20250209
DTSTAMP;VALUE=DATE:20250208
UID:2025-02-08/2025-02-09/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:清明节假期
DTSTART;VALUE=DATE:20250404
DTEND;VALUE=DATE:20250407
DTSTAMP;VALUE=DATE:20250404
UID:2025-04-04/2025-04-07/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补劳动节假期)
DTSTART;VALUE=DATE:20250427
DTEND;VALUE=DATE:20250428
DTSTAMP;VALUE=DATE:20250427
UID:2025-04-27/2025-04-28/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:劳动节假期
DTSTART;VALUE=DATE:20250501
DTEND;VALUE=DATE:20250506
DTSTAMP;VALUE=DATE:20250501
UID:2025-05-01/2025-05-06/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:端午节假期
DTSTART;VALUE=DATE:20250531
DTEND;VALUE=DATE:20250603
DTSTAMP;VALUE=DATE:20250531
UID:2025-05-31/2025-06-03/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节、中秋节假期)
DTSTART;VALUE=DATE:20250928
DTEND;VALUE=DATE:20250929
DTSTAMP;VALUE=DATE:20250928
UID:2025-09-28/2025-09-29/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:国庆节、中秋节假期
DTSTART;VALUE=DATE:20251001
DTEND;VALUE=DATE:20251009
DTSTAMP;VALUE=DATE:20251001
UID:2025-10-01/2025-10-09/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节、中秋节假期)
DTSTART;VALUE=DATE:20251011
DTEND;VALUE=DATE:20251012
DTSTAMP;VALUE=DATE:20251011
UID:2025-10-11/2025-10-12/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:元旦假期
DTSTART;VALUE=DATE:20260101
DTEND;VALUE=DATE:20260104
DTSTAMP;VALUE=DATE:20260101
UID:2026-01-01/2026-01-04/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补元旦假期)
DTSTART;VALUE=DATE:20260104
DTEND;VALUE=DATE:20260105
DTSTAMP;VALUE=DATE:20260104
UID:2026-01-04/2026-01-05/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20260214
DTEND;VALUE=DATE:20260215
DTSTAMP;VALUE=DATE:20260214
UID:2026-02-14/2026-02-15/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:春节假期
DTSTART;VALUE=DATE:20260215
DTEND;VALUE=DATE:20260224
DTSTAMP;VALUE=DATE:20260215
UID:2026-02-15/2026-02-24/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补春节假期)
DTSTART;VALUE=DATE:20260228
DTEND;VALUE=DATE:20260301
DTSTAMP;VALUE=DATE:20260228
UID:2026-02-28/2026-03-01/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:清明节假期
DTSTART;VALUE=DATE:20260404
DTEND;VALUE=DATE:20260407
DTSTAMP;VALUE=DATE:20260404
UID:2026-04-04/2026-04-07/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:劳动节假期
DTSTART;VALUE=DATE:20260501
DTEND;VALUE=DATE:20260506
DTSTAMP;VALUE=DATE:20260501
UID:2026-05-01/2026-05-06/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补劳动节假期)
DTSTART;VALUE=DATE:20260509
DTEND;VALUE=DATE:20260510
DTSTAMP;VALUE=DATE:20260509
UID:2026-05-09/2026-05-10/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:端午节假期
DTSTART;VALUE=DATE:20260619
DTEND;VALUE=DATE:20260622
DTSTAMP;VALUE=DATE:20260619
UID:2026-06-19/2026-06-22/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节假期)
DTSTART;VALUE=DATE:20260920
DTEND;VALUE=DATE:20260921
DTSTAMP;VALUE=DATE:20260920
UID:2026-09-20/2026-09-21/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:中秋节假期
DTSTART;VALUE=DATE:20260925
DTEND;VALUE=DATE:20260928
DTSTAMP;VALUE=DATE:20260925
UID:2026-09-25/2026-09-28/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:国庆节假期
DTSTART;VALUE=DATE:20261001
DTEND;VALUE=DATE:20261008
DTSTAMP;VALUE=DATE:20261001
UID:2026-10-01/2026-10-08/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:上班(补国庆节假期)
DTSTART;VALUE=DATE:20261010
DTEND;VALUE=DATE:20261011
DTSTAMP;VALUE=DATE:20261010
UID:2026-10-10/2026-10-11/NateScarlet/holiday-cn
END:VEVENT
END:VCALENDAR END:VCALENDAR

100
holiday-hk.ics Normal file
View File

@@ -0,0 +1,100 @@
BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
CLASS:PUBLIC
X-WR-CALDESC:香港公众假期数据,来源:香港特别行政区政
府 1823.gov.hk。
X-WR-CALNAME:香港公众假期
BEGIN:VTIMEZONE
TZID:Asia/Shanghai
BEGIN:STANDARD
DTSTART:19700101T000000
TZOFFSETFROM:+0800
TZOFFSETTO:+0800
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
SUMMARY:一月一日假期
DTSTART;VALUE=DATE:20260101
DTEND;VALUE=DATE:20260102
DTSTAMP;VALUE=DATE:20260101
UID:2026-01-01/2026-01-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:農曆年初一假期
DTSTART;VALUE=DATE:20260217
DTEND;VALUE=DATE:20260220
DTSTAMP;VALUE=DATE:20260217
UID:2026-02-17/2026-02-20/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:耶穌受難節假期
DTSTART;VALUE=DATE:20260403
DTEND;VALUE=DATE:20260405
DTSTAMP;VALUE=DATE:20260403
UID:2026-04-03/2026-04-05/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:清明節翌日假期
DTSTART;VALUE=DATE:20260406
DTEND;VALUE=DATE:20260408
DTSTAMP;VALUE=DATE:20260406
UID:2026-04-06/2026-04-08/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:勞動節假期
DTSTART;VALUE=DATE:20260501
DTEND;VALUE=DATE:20260502
DTSTAMP;VALUE=DATE:20260501
UID:2026-05-01/2026-05-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:佛誕翌日假期
DTSTART;VALUE=DATE:20260525
DTEND;VALUE=DATE:20260526
DTSTAMP;VALUE=DATE:20260525
UID:2026-05-25/2026-05-26/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:端午節假期
DTSTART;VALUE=DATE:20260619
DTEND;VALUE=DATE:20260620
DTSTAMP;VALUE=DATE:20260619
UID:2026-06-19/2026-06-20/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:香港特別行政區成立紀念日假期
DTSTART;VALUE=DATE:20260701
DTEND;VALUE=DATE:20260702
DTSTAMP;VALUE=DATE:20260701
UID:2026-07-01/2026-07-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:中秋節翌日假期
DTSTART;VALUE=DATE:20260926
DTEND;VALUE=DATE:20260927
DTSTAMP;VALUE=DATE:20260926
UID:2026-09-26/2026-09-27/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:國慶日假期
DTSTART;VALUE=DATE:20261001
DTEND;VALUE=DATE:20261002
DTSTAMP;VALUE=DATE:20261001
UID:2026-10-01/2026-10-02/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:重陽節翌日假期
DTSTART;VALUE=DATE:20261019
DTEND;VALUE=DATE:20261020
DTSTAMP;VALUE=DATE:20261019
UID:2026-10-19/2026-10-20/NateScarlet/holiday-cn
END:VEVENT
BEGIN:VEVENT
SUMMARY:聖誕節假期
DTSTART;VALUE=DATE:20261225
DTEND;VALUE=DATE:20261227
DTSTAMP;VALUE=DATE:20261225
UID:2026-12-25/2026-12-27/NateScarlet/holiday-cn
END:VEVENT
END:VCALENDAR

View File

@@ -1,3 +1,7 @@
{ {
"extends": ["config:base", ":automergeMinor"] "extends": [
"config:best-practices",
":automergeMinor",
":disableDependencyDashboard"
]
} }

View File

@@ -1,4 +0,0 @@
requests==2.28.1
beautifulsoup4==4.11.1
tqdm==4.64.1
icalendar==4.1.0

View File

@@ -1,4 +1,9 @@
[ [
{
"year": 2025,
"description": "1月1日周三放假1天不调休。",
"expected": [{ "date": "2025-01-01", "isOffDay": true }]
},
{ {
"year": 2019, "year": 2019,
"description": "2018年12月30日至2019年1月1日放假调休共3天。2018年12月29日星期六上班。", "description": "2018年12月30日至2019年1月1日放假调休共3天。2018年12月29日星期六上班。",

90
fetch_holidays.py → scripts/fetch.py Executable file → Normal file
View File

@@ -11,17 +11,16 @@ from typing import Iterator, List, Optional, Tuple
import bs4 import bs4
import requests import requests
SEARCH_URL = "http://sousuo.gov.cn/s.htm"
PAPER_EXCLUDE = [ PAPER_EXCLUDE = [
"http://www.gov.cn/zhengce/content/2014-09/29/content_9102.htm", "http://www.gov.cn/zhengce/zhengceku/2014-09/29/content_9102.htm",
"http://www.gov.cn/zhengce/content/2015-02/09/content_9466.htm", "http://www.gov.cn/zhengce/zhengceku/2015-02/09/content_9466.htm",
] ]
PAPER_INCLUDE = { PAPER_INCLUDE = {
2015: ["http://www.gov.cn/zhengce/content/2015-05/13/content_9742.htm"] 2015: ["http://www.gov.cn/zhengce/zhengceku/2015-05/13/content_9742.htm"]
} }
PRE_PARSED_PAPERS = { PRE_PARSED_PAPERS = {
"http://www.gov.cn/zhengce/content/2015-05/13/content_9742.htm": [ "http://www.gov.cn/zhengce/zhengceku/2015-05/13/content_9742.htm": [
{ {
"name": "抗日战争暨世界反法西斯战争胜利70周年纪念日", "name": "抗日战争暨世界反法西斯战争胜利70周年纪念日",
"date": date(2015, 9, 3), "date": date(2015, 9, 3),
@@ -43,7 +42,7 @@ PRE_PARSED_PAPERS = {
"isOffDay": False, "isOffDay": False,
}, },
], ],
"http://www.gov.cn/zhengce/content/2020-01/27/content_5472352.htm": [ "http://www.gov.cn/zhengce/zhengceku/2020-01/27/content_5472352.htm": [
{ {
"name": "春节", "name": "春节",
"date": date(2020, 1, 31), "date": date(2020, 1, 31),
@@ -77,6 +76,40 @@ def _raise_for_status_200(resp: requests.Response):
) )
def _get_paper_urls(year: int) -> Iterator[str]:
has_next_page = True
page_index = 0
while has_next_page:
resp = requests.get(
"https://sousuo.www.gov.cn/search-gov/data",
params={
"t": "zhengcelibrary_gw",
"p": page_index,
"n": 5,
"q": "假期 %d" % (year,),
"pcodeJiguan": "国办发明电",
"puborg": "国务院办公厅",
"filetype": "通知",
"sort": "pubtime",
},
)
_raise_for_status_200(resp)
data = resp.json()
if data["code"] == 1001:
# no match
return
assert data["code"] == 200, "%s: %s: %s" % (
resp.url,
data["code"],
data["msg"],
)
for i in data["searchVO"]["listVO"]:
if str(year) in i["title"]:
yield i["url"]
page_index += 1
has_next_page = page_index < data["searchVO"]["totalpage"]
def get_paper_urls(year: int) -> List[str]: def get_paper_urls(year: int) -> List[str]:
"""Find year related paper urls. """Find year related paper urls.
@@ -84,29 +117,14 @@ def get_paper_urls(year: int) -> List[str]:
year (int): eg. 2018 year (int): eg. 2018
Returns: Returns:
List[str]: Urls newlest first. List[str]: Urls sort by publish time.
""" """
resp = requests.get( ret = [i for i in _get_paper_urls(year) if i not in PAPER_EXCLUDE]
SEARCH_URL,
params={
"t": "paper",
"advance": "true",
"title": year,
"q": "假期",
"pcodeJiguan": "国办发明电",
"puborg": "国务院办公厅",
},
)
_raise_for_status_200(resp)
ret = re.findall(
r'<li class="res-list".*?<a href="(.+?)".*?</li>', resp.text, flags=re.S
)
ret = [i for i in ret if i not in PAPER_EXCLUDE]
ret += PAPER_INCLUDE.get(year, []) ret += PAPER_INCLUDE.get(year, [])
ret.sort() ret.sort()
if not ret and date.today().year >= year: if not ret and date.today().year >= year:
raise RuntimeError("could not found papers for %d" % year) raise RuntimeError("could not found papers for %d" % (year,))
return ret return ret
@@ -120,18 +138,19 @@ def get_paper(url: str) -> str:
str: Extracted paper text. str: Extracted paper text.
""" """
assert re.match(
r"http://www.gov.cn/zhengce/content/\d{4}-\d{2}/\d{2}/content_\d+.htm", url
), "Site changed, need human verify"
response = requests.get(url) response = requests.get(url)
_raise_for_status_200(response) _raise_for_status_200(response)
response.encoding = "utf-8" response.encoding = "utf-8"
soup = bs4.BeautifulSoup(response.text, features="html.parser") soup = bs4.BeautifulSoup(response.text, features="html.parser")
container = soup.find("td", class_="b12c") container = soup.find(id="UCAP-CONTENT")
assert container, f"Can not get paper container from url: {url}" assert isinstance(
ret = container.get_text().replace("\u3000\u3000", "\n") container, bs4.Tag
assert ret, f"Can not get paper content from url: {url}" ), f"Can not get paper container from url: {url}"
p = bs4.BeautifulSoup(
container.decode().replace("<br/>", "</p><p>"), features="html.parser"
).find_all("p")
ret = "\n".join((i.get_text().strip() for i in p))
assert ret, f"can not get paper content from url: {url}"
return ret return ret
@@ -258,7 +277,7 @@ class DescriptionParser:
class SentenceParser: class SentenceParser:
"""Parser for holiday shift description sentence.""" """Parser for holiday shift description sentence."""
def __init__(self, parent: DescriptionParser, sentence): def __init__(self, parent: DescriptionParser, sentence: str):
self.parent = parent self.parent = parent
self.sentence = sentence self.sentence = sentence
@@ -297,7 +316,8 @@ class SentenceParser:
def _extract_dates_2(self, value: str) -> Iterator[date]: def _extract_dates_2(self, value: str) -> Iterator[date]:
value = re.sub(r".+?", "", value) value = re.sub(r".+?", "", value)
match = re.findall( match = re.findall(
r"(?:(\d+)年)?(?:(\d+)月)?(\d+)日(?:至|-|—)(?:(\d+)年)?(?:(\d+)月)?(\d+)日", value r"(?:(\d+)年)?(?:(\d+)月)?(\d+)日(?:至|-|—)(?:(\d+)年)?(?:(\d+)月)?(\d+)日",
value,
) )
for groups in match: for groups in match:
groups = [_cast_int(i) for i in groups] groups = [_cast_int(i) for i in groups]
@@ -338,6 +358,8 @@ class SentenceParser:
yield i yield i
def _parse_rest_1(self): def _parse_rest_1(self):
if self.sentence.startswith(""):
return
match = re.match(r"(.+)(放假|补休|调休|公休)+(?:\d+天)?$", self.sentence) match = re.match(r"(.+)(放假|补休|调休|公休)+(?:\d+天)?$", self.sentence)
if match: if match:
for i in self.extract_dates(match.group(1)): for i in self.extract_dates(match.group(1)):

45
scripts/fetch_hk.py Normal file
View File

@@ -0,0 +1,45 @@
"""Fetch Hong Kong public holiday data from 1823.gov.hk."""
import datetime
import requests
# Traditional Chinese names, consistent with CN data format
HK_ICAL_URL = "https://www.1823.gov.hk/common/ical/tc.json"
# Earliest year available from the 1823.gov.hk API
HK_START_YEAR = 2024
def fetch_hk_holiday(year: int) -> dict:
"""Fetch HK public holidays for a given year.
HK has no makeup work day (调休) concept, so all entries are isOffDay=True.
Data coverage starts from HK_START_YEAR.
"""
response = requests.get(HK_ICAL_URL)
response.raise_for_status()
data = response.json()
events = data["vcalendar"][0]["vevent"]
days = []
for event in events:
dtstart = event["dtstart"][0] # "YYYYMMDD"
date = datetime.date(int(dtstart[:4]), int(dtstart[4:6]), int(dtstart[6:8]))
if date.year != year:
continue
days.append(
{
"name": event["summary"],
"date": date.isoformat(),
"isOffDay": True,
}
)
days.sort(key=lambda d: d["date"])
return {
"year": year,
"papers": [HK_ICAL_URL],
"days": days,
}

83
scripts/fetch_test.py Normal file
View File

@@ -0,0 +1,83 @@
"""Test module `fetch_holidays`. """
import json
import pytest
from fetch import (
CustomJSONEncoder,
DescriptionParser,
get_paper,
get_paper_urls,
get_rules,
)
from filetools import workspace_path
def test_get_paper_urls():
assert get_paper_urls(2019) == [
"http://www.gov.cn/zhengce/zhengceku/2018-12/06/content_5346276.htm",
"http://www.gov.cn/zhengce/zhengceku/2019-03/22/content_5375877.htm",
]
def test_get_rules():
assert list(
get_rules(
get_paper(
"http://www.gov.cn/zhengce/zhengceku/2019-03/22/content_5375877.htm"
)
)
) == [("劳动节", "2019年5月1日至4日放假调休共4天。4月28日星期日、5月5日星期日上班。")]
def test_get_rules_2023():
got = list(
get_rules(
get_paper(
"http://www.gov.cn/zhengce/zhengceku/2022-12/08/content_5730844.htm"
)
)
)
assert got == [
("元旦", "2022年12月31日至2023年1月2日放假调休共3天。"),
(
"春节",
"1月21日至27日放假调休共7天。1月28日星期六、1月29日星期日上班。",
),
("清明节", "4月5日放假共1天。"),
(
"劳动节",
"4月29日至5月3日放假调休共5天。4月23日星期日、5月6日星期六上班。",
),
("端午节", "6月22日至24日放假调休共3天。6月25日星期日上班。"),
(
"中秋节、国庆节",
"9月29日至10月6日放假调休共8天。10月7日星期六、10月8日星期日上班。",
),
]
def _normalize(iterable):
return sorted(
json.loads(json.dumps(list(iterable), cls=CustomJSONEncoder)),
key=lambda x: x["date"],
)
def _description_parsing_cases():
with open(
workspace_path("scripts", "description_parsing_cases.json"),
"r",
encoding="utf-8",
) as f:
return json.load(f)
@pytest.mark.parametrize("case", _description_parsing_cases())
def test_parse_description(case):
year, description, expected = case["year"], case["description"], case["expected"]
assert _normalize(DescriptionParser(description, year).parse()) == _normalize(
expected
), case

View File

@@ -5,6 +5,5 @@ import os
__dirname__ = os.path.abspath(os.path.dirname(__file__)) __dirname__ = os.path.abspath(os.path.dirname(__file__))
def _file_path(*other): def workspace_path(*other):
return os.path.join(os.path.dirname(__dirname__), *other)
return os.path.abspath(os.path.join(__dirname__, *other))

View File

@@ -60,11 +60,16 @@ def _iter_date_ranges(days: Sequence[dict]) -> Iterator[Tuple[dict, dict]]:
yield fr, to yield fr, to
def generate_ics(days: Sequence[dict], filename: Text) -> None: def generate_ics(
days: Sequence[dict],
filename: Text,
cal_name: str = "中国法定节假日",
cal_desc: str = "中国法定节假日数据,自动每日抓取国务院公告。",
) -> None:
"""Generate ics from days.""" """Generate ics from days."""
cal = Calendar() cal = Calendar()
cal.add("X-WR-CALNAME", "中国法定节假日") cal.add("X-WR-CALNAME", cal_name)
cal.add("X-WR-CALDESC", "中国法定节假日数据,自动每日抓取国务院公告。") cal.add("X-WR-CALDESC", cal_desc)
cal.add("VERSION", "2.0") cal.add("VERSION", "2.0")
cal.add("METHOD", "PUBLISH") cal.add("METHOD", "PUBLISH")
cal.add("CLASS", "PUBLIC") cal.add("CLASS", "PUBLIC")

239
scripts/update.py Normal file
View File

@@ -0,0 +1,239 @@
#!/usr/bin/env python3
"""Script for updating data. """
import argparse
import json
import os
import re
import subprocess
from datetime import datetime, timedelta, tzinfo
from tempfile import mkstemp
from typing import Iterator
from zipfile import ZipFile
from tqdm import tqdm
from fetch import CustomJSONEncoder, fetch_holiday
from fetch_hk import HK_START_YEAR, fetch_hk_holiday
from generate_ics import generate_ics
from filetools import workspace_path
SCHEMA_URL = "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/schema.json"
GITHUB_RAW_BASE = "https://raw.githubusercontent.com/NateScarlet/holiday-cn/master"
REGIONS = {
"cn": {
"fetch": fetch_holiday,
"start_year": 2007,
"subdir": None,
"main_ics_name": "holiday-cn.ics",
"cal_name": "中国法定节假日",
"cal_desc": "中国法定节假日数据,自动每日抓取国务院公告。",
},
"hk": {
"fetch": fetch_hk_holiday,
"start_year": HK_START_YEAR,
"subdir": "hk",
"main_ics_name": "holiday-hk.ics",
"cal_name": "香港公众假期",
"cal_desc": "香港公众假期数据,来源:香港特别行政区政府 1823.gov.hk。",
},
}
class ChinaTimezone(tzinfo):
"""Timezone of china."""
def tzname(self, dt):
return "UTC+8"
def utcoffset(self, dt):
return timedelta(hours=8)
def dst(self, dt):
return timedelta()
def _region_paths(region: str, year: int):
"""Return (json_path, ics_path, id_url) for a region and year."""
subdir = REGIONS[region]["subdir"]
if subdir:
os.makedirs(workspace_path(subdir), exist_ok=True)
json_path = workspace_path(subdir, f"{year}.json")
ics_path = workspace_path(subdir, f"{year}.ics")
id_url = f"{GITHUB_RAW_BASE}/{subdir}/{year}.json"
else:
json_path = workspace_path(f"{year}.json")
ics_path = workspace_path(f"{year}.ics")
id_url = f"{GITHUB_RAW_BASE}/{year}.json"
return json_path, ics_path, id_url
def update_data(year: int, region: str = "cn") -> Iterator[str]:
"""Update and store data for a year and region."""
cfg = REGIONS[region]
json_path, ics_path, id_url = _region_paths(region, year)
data = cfg["fetch"](year)
with open(json_path, "w", encoding="utf-8", newline="\n") as f:
json.dump(
dict(
(
("$schema", SCHEMA_URL),
("$id", id_url),
*data.items(),
)
),
f,
indent=4,
ensure_ascii=False,
cls=CustomJSONEncoder,
)
yield json_path
generate_ics(
data["days"],
ics_path,
cal_name=cfg["cal_name"],
cal_desc=cfg["cal_desc"],
)
yield ics_path
def update_main_ics(fr_year: int, to_year: int, region: str = "cn"):
cfg = REGIONS[region]
subdir = cfg["subdir"]
all_days = []
for year in range(fr_year, to_year + 1):
if subdir:
filename = workspace_path(subdir, f"{year}.json")
else:
filename = workspace_path(f"{year}.json")
if not os.path.isfile(filename):
continue
with open(filename, "r", encoding="utf8") as inf:
data = json.loads(inf.read())
all_days.extend(data.get("days", []))
filename = workspace_path(cfg["main_ics_name"])
generate_ics(
all_days,
filename,
cal_name=cfg["cal_name"],
cal_desc=cfg["cal_desc"],
)
return filename
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"--all",
action="store_true",
help="Update all years since each region's start year, default is this year and next year",
)
parser.add_argument(
"--release",
action="store_true",
help="create new release if repository data is not up to date",
)
parser.add_argument(
"--region",
choices=list(REGIONS.keys()),
default=None,
help="Region to update (default: all regions)",
)
args = parser.parse_args()
now = datetime.now(ChinaTimezone())
is_release = args.release
regions_to_update = list(REGIONS.keys()) if args.region is None else [args.region]
filenames = []
for region in regions_to_update:
cfg = REGIONS[region]
year_start = cfg["start_year"] if args.all else max(cfg["start_year"], now.year)
progress = tqdm(range(year_start, now.year + 2))
for year in progress:
progress.set_description(f"Updating {region} {year}")
filenames += list(update_data(year, region))
progress.set_description(f"Updating {cfg['main_ics_name']}")
filenames.append(update_main_ics(now.year - 4, now.year + 1, region))
print("")
subprocess.run(["git", "add", *filenames], check=True)
diff = subprocess.run(
["git", "diff", "--stat", "--cached"],
check=True,
stdout=subprocess.PIPE,
encoding="utf-8",
).stdout
if not diff:
print("Already up to date.")
return
if not is_release:
print("Updated repository data, skip release since not specified `--release`")
return
subprocess.run(
[
"git",
"commit",
"-m",
"chore(release): update holiday data",
"-m",
"[skip ci]",
],
check=True,
)
subprocess.run(["git", "push"], check=True)
tag = now.strftime("%Y.%m.%d")
temp_note_fd, temp_note_name = mkstemp()
with open(temp_note_fd, "w", encoding="utf-8") as f:
f.write(tag + "\n\n```diff\n" + diff + "\n```\n")
os.makedirs(workspace_path("dist"), exist_ok=True)
zip_path = workspace_path("dist", f"holiday-cn-{tag}.zip")
pack_data(zip_path)
subprocess.run(
[
"gh",
"release",
"create",
"-F",
temp_note_name,
tag,
f"{zip_path}#JSON数据",
],
check=True,
)
os.unlink(temp_note_name)
def pack_data(file):
"""Pack all region JSON data into a zip file."""
zip_file = ZipFile(file, "w")
# Root-level {year}.json files (CN)
for name in os.listdir(workspace_path()):
if re.match(r"\d+\.json", name):
zip_file.write(workspace_path(name), name)
# Subdirectory region files (e.g. hk/{year}.json)
for region, cfg in REGIONS.items():
subdir = cfg["subdir"]
if not subdir:
continue
subdir_path = workspace_path(subdir)
if not os.path.isdir(subdir_path):
continue
for name in os.listdir(subdir_path):
if re.match(r"\d+\.json", name):
zip_file.write(workspace_path(subdir, name), f"{subdir}/{name}")
if __name__ == "__main__":
main()

View File

View File

@@ -1,56 +0,0 @@
"""Test module `fetch_holidays`. """
import json
import pytest
from fetch_holidays import (
CustomJSONEncoder,
DescriptionParser,
get_paper,
get_paper_urls,
get_rules,
)
from .filetools import _file_path
def test_get_paper_urls():
assert get_paper_urls(2019) == [
"http://www.gov.cn/zhengce/content/2018-12/06/content_5346276.htm",
"http://www.gov.cn/zhengce/content/2019-03/22/content_5375877.htm",
]
def test_get_rules():
assert list(
get_rules(
get_paper(
"http://www.gov.cn/zhengce/content/2019-03/22/content_5375877.htm"
)
)
) == [("劳动节", "2019年5月1日至4日放假调休共4天。4月28日星期日、5月5日星期日上班。")]
def _normalize(iterable):
return sorted(
json.loads(json.dumps(list(iterable), cls=CustomJSONEncoder)),
key=lambda x: x["date"],
)
def _description_parsing_cases():
with open(
_file_path("description_parsing_cases.json"),
"r",
encoding="utf-8",
) as f:
return json.load(f)
@pytest.mark.parametrize("case", _description_parsing_cases())
def test_parse_description(case):
year, description, expected = case["year"], case["description"], case["expected"]
assert _normalize(DescriptionParser(description, year).parse()) == _normalize(
expected
), case

181
update.py
View File

@@ -1,181 +0,0 @@
#!/usr/bin/env python3
"""Script for updating data. """
import argparse
import json
import os
import re
import subprocess
from datetime import datetime, timedelta, tzinfo
from tempfile import mkstemp
from typing import Iterator
from zipfile import ZipFile
from tqdm import tqdm
from fetch_holidays import CustomJSONEncoder, fetch_holiday
from generate_ics import generate_ics
class ChinaTimezone(tzinfo):
"""Timezone of china."""
def tzname(self, dt):
return "UTC+8"
def utcoffset(self, dt):
return timedelta(hours=8)
def dst(self, dt):
return timedelta()
__dirname__ = os.path.abspath(os.path.dirname(__file__))
def _file_path(*other):
return os.path.join(__dirname__, *other)
def update_data(year: int) -> Iterator[str]:
"""Update and store data for a year."""
json_filename = _file_path(f"{year}.json")
ics_filename = _file_path(f"{year}.ics")
with open(json_filename, "w", encoding="utf-8", newline="\n") as f:
data = fetch_holiday(year)
json.dump(
dict(
(
(
"$schema",
"https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/schema.json",
),
(
"$id",
f"https://raw.githubusercontent.com/NateScarlet/holiday-cn/master/{year}.json",
),
*data.items(),
)
),
f,
indent=4,
ensure_ascii=False,
cls=CustomJSONEncoder,
)
yield json_filename
generate_ics(data["days"], ics_filename)
yield ics_filename
def update_main_ics(fr_year, to_year):
all_days = []
for year in range(fr_year, to_year + 1):
filename = _file_path(f"{year}.json")
if not os.path.isfile(filename):
continue
with open(filename, "r", encoding="utf8") as inf:
data = json.loads(inf.read())
all_days.extend(data.get("days"))
filename = _file_path("holiday-cn.ics")
generate_ics(
all_days,
filename,
)
return filename
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"--all",
action="store_true",
help="Update all years since 2007, default is this year and next year",
)
parser.add_argument(
"--release",
action="store_true",
help="create new release if repository data is not up to date",
)
args = parser.parse_args()
now = datetime.now(ChinaTimezone())
is_release = args.release
filenames = []
progress = tqdm(range(2007 if args.all else now.year, now.year + 2))
for i in progress:
progress.set_description(f"Updating {i} data")
filenames += list(update_data(i))
progress.set_description("Updating holiday-cn.ics")
filenames.append(update_main_ics(now.year - 4, now.year + 1))
print("")
subprocess.run(["hub", "add", *filenames], check=True)
diff = subprocess.run(
["hub", "diff", "--stat", "--cached", "*.json", "*.ics"],
check=True,
stdout=subprocess.PIPE,
encoding="utf-8",
).stdout
if not diff:
print("Already up to date.")
return
if not is_release:
print("Updated repository data, skip release since not specified `--release`")
return
subprocess.run(
[
"hub",
"commit",
"-m",
"chore(release): update holiday data",
"-m",
"[skip ci]",
],
check=True,
)
subprocess.run(["hub", "push"], check=True)
tag = now.strftime("%Y.%m.%d")
temp_note_fd, temp_note_name = mkstemp()
with open(temp_note_fd, "w", encoding="utf-8") as f:
f.write(tag + "\n\n```diff\n" + diff + "\n```\n")
os.makedirs(_file_path("dist"), exist_ok=True)
zip_path = _file_path("dist", f"holiday-cn-{tag}.zip")
pack_data(zip_path)
subprocess.run(
[
"hub",
"release",
"create",
"-F",
temp_note_name,
"-a",
f"{zip_path}#JSON数据",
tag,
],
check=True,
)
os.unlink(temp_note_name)
def pack_data(file):
"""Pack data json in zip file."""
zip_file = ZipFile(file, "w")
for i in os.listdir(__dirname__):
if not re.match(r"\d+\.json", i):
continue
zip_file.write(_file_path(i), i)
if __name__ == "__main__":
main()