refactor code

This commit is contained in:
muhac 2023-11-07 08:23:04 +08:00 committed by Muhan Li
parent 71d393647c
commit 7b26f593c6
10 changed files with 1117 additions and 1078 deletions

View File

@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
fetch-depth: 2
@ -38,34 +38,17 @@ jobs:
ghc-version: 9.2.8
cabal-version: 3.10.1.0
- name: Configure and build
run: |
cabal configure --enable-tests --enable-benchmarks --disable-documentation
cabal build all
- name: Build parser
run: cabal build
- name: Generate ICS files
run: cabal run
- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v4
uses: stefanzweifel/git-auto-commit-action@v5
with:
file_pattern: docs/*.html docs/*.ics data/*.txt
file_pattern: README.md docs/* data/*
commit_message: update calendar data automatically
commit_user_name: Muhan Li
commit_user_email: limuhan@msn.com
commit_author: Muhan Li <limuhan@msn.com>
- name: Get last commit message
id: last-commit-message
run: echo "msg=$(git log -1 --pretty=%s)" >> $GITHUB_OUTPUT
- name: Update README
uses: stefanzweifel/git-auto-commit-action@v4
with:
file_pattern: README.md
commit_message: ${{ steps.last-commit-message.outputs.msg }}
commit_user_name: Muhan Li
commit_user_email: limuhan@msn.com
commit_options: '--amend --no-edit'
push_options: '--force'
skip_fetch: true

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,553 +4,553 @@ PRODID:-//Rank Technology//Chinese Holidays//EN
X-WR-CALNAME:中国节假日安排(补班)
BEGIN:VEVENT
UID:50e76d00-0000-0002-0000-000200000001
UID:20130105-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20130105
SUMMARY:元旦补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:50e8be80-0000-0002-0000-000200000002
UID:20130106-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20130106
SUMMARY:元旦补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:511ecc00-0000-0002-0000-000200000001
UID:20130216-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20130216
SUMMARY:春节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:51201d80-0000-0002-0000-000200000002
UID:20130217-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20130217
SUMMARY:春节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:5160b700-0000-0002-0000-000100000001
UID:20130407-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20130407
SUMMARY:清明节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:517b1500-0000-0002-0000-000200000001
UID:20130427-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20130427
SUMMARY:劳动节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:517c6680-0000-0002-0000-000200000002
UID:20130428-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20130428
SUMMARY:劳动节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:51b27400-0000-0002-0000-000200000001
UID:20130608-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20130608
SUMMARY:端午节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:51b3c580-0000-0002-0000-000200000002
UID:20130609-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20130609
SUMMARY:端午节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:523e3300-0000-0002-0000-000100000001
UID:20130922-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20130922
SUMMARY:中秋节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:52476d80-0000-0002-0000-000200000001
UID:20130929-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20130929
SUMMARY:国庆节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:52589100-0000-0002-0000-000200000002
UID:20131012-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20131012
SUMMARY:国庆节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:52e45000-0000-0002-0000-000200000001
UID:20140126-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20140126
SUMMARY:春节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:52f57380-0000-0002-0000-000200000002
UID:20140208-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20140208
SUMMARY:春节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:53658300-0000-0002-0000-000100000001
UID:20140504-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20140504
SUMMARY:劳动节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:54274f80-0000-0002-0000-000200000001
UID:20140928-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20140928
SUMMARY:国庆节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:54387300-0000-0002-0000-000200000002
UID:20141011-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20141011
SUMMARY:国庆节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:54a88280-0000-0002-0000-000100000001
UID:20150104-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20150104
SUMMARY:元旦补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:54dfe180-0000-0002-0000-000200000001
UID:20150215-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20150215
SUMMARY:春节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:54f10500-0000-0002-0000-000200000002
UID:20150228-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20150228
SUMMARY:春节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:56185500-0000-0002-0000-000100000001
UID:20151010-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20151010
SUMMARY:国庆节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:56b53780-0000-0002-0000-000200000001
UID:20160206-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20160206
SUMMARY:春节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:56bfc380-0000-0002-0000-000200000002
UID:20160214-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20160214
SUMMARY:春节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:575ca600-0000-0002-0000-000100000001
UID:20160612-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20160612
SUMMARY:端午节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:57ddd900-0000-0002-0000-000100000001
UID:20160918-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20160918
SUMMARY:中秋节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:57f83700-0000-0002-0000-000200000001
UID:20161008-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20161008
SUMMARY:国庆节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:57f98880-0000-0002-0000-000200000002
UID:20161009-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20161009
SUMMARY:国庆节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:5883f600-0000-0002-0000-000200000001
UID:20170122-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20170122
SUMMARY:春节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:58951980-0000-0002-0000-000200000002
UID:20170204-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20170204
SUMMARY:春节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:58deed80-0000-0002-0000-000100000001
UID:20170401-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20170401
SUMMARY:清明节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:5928c180-0000-0002-0000-000100000001
UID:20170527-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20170527
SUMMARY:端午节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:59cede80-0000-0002-0000-000100000001
UID:20170930-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20170930
SUMMARY:中秋节、国庆节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:5a7f8780-0000-0002-0000-000200000001
UID:20180211-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20180211
SUMMARY:春节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:5a90ab00-0000-0002-0000-000200000002
UID:20180224-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20180224
SUMMARY:春节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:5ac95b80-0000-0002-0000-000100000001
UID:20180408-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20180408
SUMMARY:清明节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:5ae3b980-0000-0002-0000-000100000001
UID:20180428-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20180428
SUMMARY:劳动节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:5baec080-0000-0002-0000-000200000001
UID:20180929-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20180929
SUMMARY:国庆节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:5bb01200-0000-0002-0000-000200000002
UID:20180930-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20180930
SUMMARY:国庆节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:5c198a00-0000-0002-0000-000100000001
UID:20181219-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20181219
SUMMARY:元旦补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:5c54dd80-0000-0002-0000-000200000001
UID:20190202-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20190202
SUMMARY:春节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:5c562f00-0000-0002-0000-000200000002
UID:20190203-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20190203
SUMMARY:春节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:5d8ff400-0000-0002-0000-000200000001
UID:20190929-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20190929
SUMMARY:国庆节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:5da11780-0000-0002-0000-000200000002
UID:20191012-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20191012
SUMMARY:国庆节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:5e239c00-0000-0002-0000-000200000001
UID:20200119-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20200119
SUMMARY:春节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:5e34bf80-0000-0002-0000-000200000002
UID:20200201-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20200201
SUMMARY:春节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:5ea4cf00-0000-0002-0000-000200000001
UID:20200426-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20200426
SUMMARY:劳动节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:5eb5f280-0000-0002-0000-000200000002
UID:20200509-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20200509
SUMMARY:劳动节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:5ef7dd80-0000-0002-0000-000100000001
UID:20200628-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20200628
SUMMARY:端午节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:5f6fd600-0000-0002-0000-000200000001
UID:20200927-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20200927
SUMMARY:国庆节、中秋节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:5f80f980-0000-0002-0000-000200000002
UID:20201010-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20201010
SUMMARY:国庆节、中秋节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:601f2d80-0000-0002-0000-000200000001
UID:20210207-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20210207
SUMMARY:春节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:60305100-0000-0002-0000-000200000002
UID:20210220-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20210220
SUMMARY:春节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:6084b100-0000-0002-0000-000200000001
UID:20210425-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20210425
SUMMARY:劳动节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:6095d480-0000-0002-0000-000200000002
UID:20210508-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20210508
SUMMARY:劳动节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:61452c00-0000-0002-0000-000100000001
UID:20210918-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20210918
SUMMARY:中秋节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:614fb800-0000-0002-0000-000200000001
UID:20210926-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20210926
SUMMARY:国庆节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:6160db80-0000-0002-0000-000200000002
UID:20211009-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20211009
SUMMARY:国庆节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:61f48380-0000-0002-0000-000200000001
UID:20220129-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20220129
SUMMARY:春节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:61f5d500-0000-0002-0000-000200000002
UID:20220130-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20220130
SUMMARY:春节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:62479200-0000-0002-0000-000100000001
UID:20220402-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20220402
SUMMARY:清明节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:62649300-0000-0002-0000-000200000001
UID:20220424-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20220424
SUMMARY:劳动节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:6275b680-0000-0002-0000-000200000002
UID:20220507-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20220507
SUMMARY:劳动节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:6340bd80-0000-0002-0000-000200000001
UID:20221008-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20221008
SUMMARY:国庆节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:63420f00-0000-0002-0000-000200000002
UID:20221009-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20221009
SUMMARY:国庆节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:63d46580-0000-0002-0000-000200000001
UID:20230128-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20230128
SUMMARY:春节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:63d5b700-0000-0002-0000-000200000002
UID:20230129-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20230129
SUMMARY:春节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:64447500-0000-0002-0000-000200000001
UID:20230423-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20230423
SUMMARY:劳动节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:64559880-0000-0002-0000-000200000002
UID:20230506-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20230506
SUMMARY:劳动节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:64978380-0000-0002-0000-000100000001
UID:20230625-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20230625
SUMMARY:端午节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:65209f80-0000-0002-0000-000200000001
UID:20231007-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20231007
SUMMARY:中秋节、国庆节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:6521f100-0000-0002-0000-000200000002
UID:20231008-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20231008
SUMMARY:中秋节、国庆节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:65bed380-0000-0002-0000-000200000001
UID:20240204-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20240204
SUMMARY:春节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:65d14880-0000-0002-0000-000200000002
UID:20240218-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20240218
SUMMARY:春节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:6611e200-0000-0002-0000-000100000001
UID:20240407-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20240407
SUMMARY:清明节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:662d9180-0000-0002-0000-000200000001
UID:20240428-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20240428
SUMMARY:劳动节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:663eb500-0000-0002-0000-000200000002
UID:20240511-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20240511
SUMMARY:劳动节补班
DESCRIPTION:补班第2天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:66e4d200-0000-0002-0000-000100000001
UID:20240914-0001-0001-0002-0000a95511fe
DTSTART;VALUE=DATE:20240914
SUMMARY:中秋节补班
DESCRIPTION:补班第1天 / 共1天
END:VEVENT
BEGIN:VEVENT
UID:66f89880-0000-0002-0000-000200000001
UID:20240929-0001-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20240929
SUMMARY:国庆节补班
DESCRIPTION:补班第1天 / 共2天
END:VEVENT
BEGIN:VEVENT
UID:6709bc00-0000-0002-0000-000200000002
UID:20241012-0002-0002-0002-0000a95511fe
DTSTART;VALUE=DATE:20241012
SUMMARY:国庆节补班
DESCRIPTION:补班第2天 / 共2天

View File

@ -24,7 +24,7 @@ description: Calendar of Public Holidays in China
-- PVP summary: +-+------- breaking API changes
-- | | +----- non-breaking API additions
-- | | | +--- code changes with no API change
version: 0.1.2.0
version: 0.2.0.0
-- A short (one-line) description of the package.
-- synopsis:
@ -54,6 +54,8 @@ build-type: Simple
-- Extra source files to be distributed with the package, such as examples, or a tutorial module.
-- extra-source-files:
-- formatting command: fourmolu --mode inplace $(git ls-files '*.hs') --indentation 2 --indent-wheres true
common warnings
ghc-options: -Wall

View File

@ -1,5 +1,6 @@
module Main where
import Data.Function (on)
import Data.List (isPrefixOf, sortBy)
import Main.Base
import Main.Input
@ -17,26 +18,22 @@ main = do
contents <- mapM (readFile . ("./data" </>)) files
-- parse data
let dataByFile = zip files contents
let dataByYear = map parseByFile dataByFile
let dataMixed = join dataByYear
-- debug log
debug dataByYear
let calendarYearly = zipWith parseFile files contents
debug calendarYearly
-- write files
writeFile "./docs/index.html" $ icsByType Both dataMixed
let calendar = calendarYearly >>= join
writeFile "./docs/index.html" $ generate calendar Both
writeFile "./docs/main.ics" $ icsByType Both dataMixed
writeFile "./docs/rest.ics" $ icsByType Rest dataMixed
writeFile "./docs/work.ics" $ icsByType Work dataMixed
writeFile "./docs/main.ics" $ generate calendar Both
writeFile "./docs/rest.ics" $ generate calendar Rest
writeFile "./docs/work.ics" $ generate calendar Work
-- Log holiday data ordered by each year
debug :: [(String, [Date], [Date])] -> IO ()
debug dataByYear = mapM_ showByYear $ sortByYear data'
where
data' = map (\(y, r, w) -> (y, sortByDate $ r ++ w)) dataByYear
sortByYear = sortBy (\(y1, _) (y2, _) -> compare y1 y2)
showByYear (year, dates) = do
putStrLn $ "\nYear" <> year
mapM_ print dates
debug :: [Yearly] -> IO ()
debug yearly =
let orderByYear = sortBy (compare `on` year) yearly
printByDate holiday = do
putStrLn $ "\nYear " ++ year holiday
mapM_ print $ sortByDate $ join holiday
in mapM_ printByDate orderByYear

View File

@ -4,47 +4,86 @@ import Data.Function (on)
import Data.List (sortBy)
import Data.Time (UTCTime, defaultTimeLocale, formatTime)
data DateType = Both | Rest | Work deriving (Enum)
data Status = Both | Rest | Work deriving (Enum)
instance Show DateType where
instance Show Status where
show Both = ""
show Rest = "假期"
show Work = "补班"
-- Title of output ics file
titleDateType :: DateType -> String
titleDateType Both = "中国节假日安排"
titleDateType flag = "中国节假日安排(" <> show flag <> ""
titleStatus :: Status -> String
titleStatus Both = "中国节假日安排"
titleStatus kind = "中国节假日安排(" ++ show kind ++ ""
-- Index of input txt file
indexDateType :: DateType -> Int
indexDateType Both = 0
indexDateType Rest = 1
indexDateType Work = 2
indexStatus :: Status -> Int
indexStatus Both = 0
indexStatus Rest = 1
indexStatus Work = 2
instance Eq Status where
(==) = (==) `on` indexStatus
data Yearly = Yearly
{ year :: String
, rest :: [Holiday]
, work :: [Holiday]
}
join :: Yearly -> [Holiday]
join y = rest y ++ work y
data HolidayRaw = HolidayRaw
{ rawName :: String
, rawRest :: String
, rawWork :: String
}
rawDate :: Status -> HolidayRaw -> String
rawDate Rest = rawRest
rawDate Work = rawWork
rawDate _ = return ""
toHolidayRaw :: [String] -> Maybe HolidayRaw
toHolidayRaw [n, r, w] = Just $ HolidayRaw n r w
toHolidayRaw _ = Nothing
data Holiday = Holiday
{ holidayGroup :: Group
, holidayDate :: Date
}
instance Show Holiday where
show (Holiday group date) = unwords [show date, show group]
toHolidays :: Group -> [Date] -> [Holiday]
toHolidays group dates = Holiday group <$> dates
data Group = Group
{ holidayStatus :: Status
, holidayName :: String
}
instance Show Group where
show (Group status name) = unwords [name, show status]
data Date = Date
{ name :: String,
time :: UTCTime,
flag :: DateType,
index :: Int,
total :: Int
{ holidayIndex :: Int
, holidayTotal :: Int
, holidayTime :: UTCTime
}
instance Show Date where
show (Date name time flag index total) =
show (Date index total time) =
unwords
[ formatTime defaultTimeLocale "%Y-%m-%d" time,
name,
show flag,
show index <> "/" <> show total
[ formatTime defaultTimeLocale "%Y-%m-%d" time
, show index ++ "/" ++ show total
]
constructDate :: String -> DateType -> (Int, Int, UTCTime) -> Date
constructDate name flag (index, total, time) = Date name time flag index total
sortByDate :: [Holiday] -> [Holiday]
sortByDate = sortBy (compare `on` holidayTime . holidayDate)
sortByDate :: [Date] -> [Date]
sortByDate = sortBy (compare `on` time)
filterByType :: DateType -> [Date] -> [Date]
filterByType Both = id
filterByType flag = filter (\(Date _ _ f _ _) -> show f == show flag)
filterByStatus :: Status -> [Holiday] -> [Holiday]
filterByStatus Both = id
filterByStatus kind = filter ((== kind) . holidayStatus . holidayGroup)

View File

@ -1,61 +1,58 @@
module Main.Input where
import Data.Char (isSpace)
import Data.List (uncons)
import Data.List.Split (splitOn)
import Data.Maybe (mapMaybe)
import Data.Time (UTCTime, addUTCTime, defaultTimeLocale, formatTime, parseTimeOrError)
import Main.Base
import System.FilePath (takeBaseName)
-- Join data from each year and each type
join :: [(String, [Date], [Date])] -> [Date]
join = concatMap (\ (_, rest, work) -> rest ++ work)
-- Parse holiday data
-- Organized by year
parseByFile :: (FilePath, String) -> (String, [Date], [Date])
parseByFile (file, content) = (year, rest, work)
parseFile :: FilePath -> String -> Yearly
parseFile file content = Yearly yearName daysRest daysWork
where
year = takeBaseName file
rest = parse content Rest
work = parse content Work
yearName = takeBaseName file
daysRest = parse content Rest
daysWork = parse content Work
-- Convert data to Date
parse :: String -> DateType -> [Date]
parse content flag = concatMap constructor $ zip (map head raw) dates
parse :: String -> Status -> [Holiday]
parse content status = zip names dates >>= uncurry toHolidays
where
constructor (name, dates) = constructDate name flag <$> dates
dates = parseDate <$> map (!! indexDateType flag) raw
raw = parseFile content
names = Group status . rawName <$> raw
dates = parseDates . rawDate status <$> raw
raw = parseRaw content
-- Parse data from file
-- Result: [[Name, RestDays, WorkDays]]
parseFile :: String -> [[String]]
parseFile content = filter ((== 3) . length) $ splitOn ";" <$> rawEvents
-- Parse raw data from file
-- Format: name;rest;work
parseRaw :: String -> [HolidayRaw]
parseRaw content = mapMaybe (toHolidayRaw . splitOn ";") eventsRaw
where
rawEvents = filter (not . null) . map (head . words) $ uncomment
uncomment = filter (not . null) . map (head . splitOn "//") $ unindent
unindent = dropWhile isSpace <$> lines content
eventsRaw = mapMaybe (fmap fst . uncons . words) uncomment
uncomment = mapMaybe (fmap fst . uncons . splitOn "//") $ lines content
-- Expand date ranges to UTCTime list
-- Support multiple date ranges separated by comma
parseDate :: String -> [(Int, Int, UTCTime)]
parseDate "" = []
parseDate range = zip3 [1 ..] (repeat $ length dates) dates
parseDates :: String -> [Date]
parseDates ranges = zipWith3 Date [1 ..] (repeat $ length dates) dates
where
dates = concatMap (parseDate' . splitOn "-") $ splitOn "," range
dates = splitOn "," ranges >>= parseDate . splitOn "-"
-- Parse date range
-- 1. like "2020.1.1"
-- 2. like "2020.1.1-2020.1.3"
parseDate' :: [String] -> [UTCTime]
parseDate' [single] = [parseTime single]
parseDate' [start, end]
| start == end = parseDate' [end]
| otherwise = first : parseDate' [second, end]
parseDate :: [String] -> [UTCTime]
parseDate [""] = []
parseDate [single] = [parseTime single]
parseDate [start, end]
| start == end = parseDate [end]
| otherwise = first : parseDate [second, end]
where
first = parseTime start
second = printTime $ addUTCTime day first
day = 24 * 60 * 60
parseDate _ = []
-- Parse date in format "2020.1.1"
parseTime :: String -> UTCTime

View File

@ -1,45 +1,46 @@
module Main.Output where
import Data.Time (defaultTimeLocale, formatTime, nominalDiffTimeToSeconds)
import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds)
import Data.Time (defaultTimeLocale, formatTime)
import Data.UUID (fromWords, toString)
import Main.Base
import Numeric (readHex)
import Text.Printf (printf)
-- Generate ics files
icsByType :: DateType -> [Date] -> String
icsByType flag dates = unlines [icsHead flag, icsBody, icsTail]
generate :: [Holiday] -> Status -> String
generate dates status = unlines [icsHead status, icsBody, icsTail]
where
icsBody = unlines $ map icsEvent $ sortByDate $ filterByType flag dates
icsBody = unlines $ map icsEvent events
events = sortByDate $ filterByStatus status dates
-- Standard ics format for the beginning
icsHead :: DateType -> String
icsHead flag =
icsHead :: Status -> String
icsHead status =
unlines
[ "BEGIN:VCALENDAR",
"VERSION:2.0",
"PRODID:-//Rank Technology//Chinese Holidays//EN",
"X-WR-CALNAME:" <> titleDateType flag
-- "X-WR-TIMEZONE:Asia/Shanghai",
[ "BEGIN:VCALENDAR"
, "VERSION:2.0"
, "PRODID:-//Rank Technology//Chinese Holidays//EN"
, "X-WR-CALNAME:" ++ titleStatus status
]
-- Standard ics format for each event
icsEvent :: Date -> String
icsEvent (Date name time flag index total) =
icsEvent :: Holiday -> String
icsEvent (Holiday (Group status name) (Date index total time)) =
unlines
[ "BEGIN:VEVENT",
"UID:" <> uuid,
"DTSTART;VALUE=DATE:" <> formatTime defaultTimeLocale "%Y%m%d" time,
"SUMMARY:" <> name <> show flag,
"DESCRIPTION:" <> show flag <> printf "第%d天 / 共%d天" index total,
"END:VEVENT"
[ "BEGIN:VEVENT"
, "UID:" ++ uuid
, "DTSTART;VALUE=DATE:" ++ formatTime defaultTimeLocale "%Y%m%d" time
, "SUMMARY:" ++ name ++ show status
, "DESCRIPTION:" ++ show status ++ printf "第%d天 / 共%d天" index total
, "END:VEVENT"
]
where
uuid = toString $ fromWords a b c d
a = floor . nominalDiffTimeToSeconds . utcTimeToPOSIXSeconds $ time
b = fromIntegral $ indexDateType flag
c = fromIntegral total
d = fromIntegral index
a = fst . head . readHex $ formatTime defaultTimeLocale "%Y%m%d" time
b = fromIntegral $ shift index + total
c = fromIntegral $ shift $ indexStatus status
d = 0xa95511fe -- 955.WLB
shift = (*) 0x10000
-- Standard ics format for the ending
icsTail :: String

View File

@ -1,208 +1,228 @@
module Main where
import Data.Function (on)
import Main.Base
import Main.Input
import System.Exit (exitFailure, exitSuccess)
import Test.HUnit
instance Eq HolidayRaw where
(==) = (==) `on` raw
raw a = (rawName a, rawRest a, rawWork a)
instance Show HolidayRaw where
show raw = unwords [rawName raw, rawRest raw, rawWork raw]
testA1 =
TestCase
( assertEqual
"A1 - case 1. like 2020.1.1 - basic"
["2020.1.1"]
$ map printTime
$ parseDate' ["2020.1.1"]
"A1 - data - basic"
[HolidayRaw "a" "b" "c"]
$ parseRaw "a;b;c"
)
testA2 =
TestCase
( assertEqual
"A2 - case 1. like 2020.1.1 - robust"
["2021.11.2"]
(map printTime $ parseDate' ["2021.11.02"])
"A2 - data - robust"
[HolidayRaw "a12" "b345" "c678"]
$ parseRaw " a12;b345;c678 "
)
testA3 =
TestCase
( assertEqual
"A3 - case 2. like 2020.1.1-2020.1.3 - basic"
["2022.1.1", "2022.1.2", "2022.1.3"]
(map printTime $ parseDate' ["2022.1.1", "2022.1.3"])
"A3 - comments - basic"
[]
$ parseRaw "//comment"
)
testA4 =
TestCase
( assertEqual
"A4 - case 2. like 2020.1.1-2020.1.3 - cross month"
["2023.2.27", "2023.2.28", "2023.3.1", "2023.3.2"]
(map printTime $ parseDate' ["2023.2.27", "2023.3.2"])
"A4 - comments - robust"
[]
$ parseRaw " // a;b;c 123 "
)
testA5 =
TestCase
( assertEqual
"A5 - case 2. like 2020.1.1-2020.1.3 - cross month 2"
["2024.2.28", "2024.2.29", "2024.3.1"]
(map printTime $ parseDate' ["2024.2.28", "2024.3.1"])
"A5 - hybrid - basic"
[HolidayRaw "a" "b" "c"]
$ parseRaw "a;b;c // d;e;f 456 "
)
testA6 =
TestCase
( assertEqual
"A6 - case 2. like 2020.1.1-2020.1.3 - cross year"
["2025.12.30", "2025.12.31", "2026.1.1", "2026.1.2"]
(map printTime $ parseDate' ["2025.12.30", "2026.1.2"])
"A6 - hybrid - robust"
[HolidayRaw "a" "b" "c"]
$ parseRaw " a;b;c 123 // d;e;f 456 "
)
testA7 =
TestCase
( assertEqual
"A7 - empty - basic"
[]
$ parseRaw ""
)
testA8 =
TestCase
( assertEqual
"A8 - empty - robust"
[]
$ parseRaw " // "
)
testA9 =
TestCase
( assertEqual
"A9 - multi-line"
[HolidayRaw "a" "b" "c", HolidayRaw "d" "e" "f"]
$ parseRaw . unlines
$ [ "// INTRO"
, ""
, "a;b;c // dp1"
, "// comment"
, "d;e;f // dp2"
, "END // TEST"
]
)
testB1 =
TestCase
( assertEqual
"B1 - case 1. like 2020.1.1 - a1 2"
[(1, 2, "2020.1.1"), (2, 2, "2020.1.3")]
$ map (\(a, b, c) -> (a, b, printTime c))
$ parseDate "2020.1.1,2020.1.3"
"B1 - case 1. like 2020.1.1 - basic"
["2020.1.1"]
$ map printTime
$ parseDate ["2020.1.1"]
)
testB2 =
TestCase
( assertEqual
"B2 - case 1. like 2020.1.1 - a1 3"
[(1, 3, "2020.1.1"), (2, 3, "2020.1.3"), (3, 3, "2020.1.5")]
$ map (\(a, b, c) -> (a, b, printTime c))
$ parseDate "2020.1.1,2020.1.3,2020.1.5"
"B2 - case 1. like 2020.1.1 - robust"
["2021.11.2"]
(map printTime $ parseDate ["2021.11.02"])
)
testB3 =
TestCase
( assertEqual
"B3 - case 2. like 2020.1.1-2020.1.3 - a3 2"
[(1, 4, "2020.1.1"), (2, 4, "2020.1.2"), (3, 4, "2020.1.6"), (4, 4, "2020.1.7")]
$ map (\(a, b, c) -> (a, b, printTime c))
$ parseDate "2020.1.1-2020.1.2,2020.1.6-2020.1.7"
"B3 - case 2. like 2020.1.1-2020.1.3 - basic"
["2022.1.1", "2022.1.2", "2022.1.3"]
(map printTime $ parseDate ["2022.1.1", "2022.1.3"])
)
testB4 =
TestCase
( assertEqual
"B4 - case 2. like 2020.1.1-2020.1.3 - a1 a3"
[(1, 4, "2020.1.1"), (2, 4, "2020.1.2"), (3, 4, "2020.1.3"), (4, 4, "2020.1.6")]
$ map (\(a, b, c) -> (a, b, printTime c))
$ parseDate "2020.1.1-2020.1.3,2020.1.6"
"B4 - case 2. like 2020.1.1-2020.1.3 - cross month"
["2023.2.27", "2023.2.28", "2023.3.1", "2023.3.2"]
(map printTime $ parseDate ["2023.2.27", "2023.3.2"])
)
testB5 =
TestCase
( assertEqual
"B5 - case 2. like 2020.1.1-2020.1.3 - a3 a1"
[(1, 5, "2019.12.6"), (2, 5, "2020.1.1"), (3, 5, "2020.1.2"), (4, 5, "2020.1.3"), (5, 5, "2021.11.11")]
$ map (\(a, b, c) -> (a, b, printTime c))
$ parseDate "2019.12.6,2020.1.1-2020.1.3,2021.11.11"
"B5 - case 2. like 2020.1.1-2020.1.3 - cross month 2"
["2024.2.28", "2024.2.29", "2024.3.1"]
(map printTime $ parseDate ["2024.2.28", "2024.3.1"])
)
testB6 =
TestCase
( assertEqual
"B6 - case 2. like 2020.1.1-2020.1.3 - cross year"
["2025.12.30", "2025.12.31", "2026.1.1", "2026.1.2"]
(map printTime $ parseDate ["2025.12.30", "2026.1.2"])
)
testC1 =
TestCase
( assertEqual
"C1 - data - basic"
[["a", "b", "c"]]
$ parseFile "a;b;c"
"C1 - case 1. like 2020.1.1 - a1 2"
[(1, 2, "2020.1.1"), (2, 2, "2020.1.3")]
$ map (\(Date a b c) -> (a, b, printTime c))
$ parseDates "2020.1.1,2020.1.3"
)
testC2 =
TestCase
( assertEqual
"C2 - data - robust"
[["a12", "b345", "c678"]]
$ parseFile " a12;b345;c678 "
"C2 - case 1. like 2020.1.1 - a1 3"
[(1, 3, "2020.1.1"), (2, 3, "2020.1.3"), (3, 3, "2020.1.5")]
$ map (\(Date a b c) -> (a, b, printTime c))
$ parseDates "2020.1.1,2020.1.3,2020.1.5"
)
testC3 =
TestCase
( assertEqual
"C3 - comments - basic"
[]
$ parseFile "//comment"
"C3 - case 2. like 2020.1.1-2020.1.3 - a3 2"
[(1, 4, "2020.1.1"), (2, 4, "2020.1.2"), (3, 4, "2020.1.6"), (4, 4, "2020.1.7")]
$ map (\(Date a b c) -> (a, b, printTime c))
$ parseDates "2020.1.1-2020.1.2,2020.1.6-2020.1.7"
)
testC4 =
TestCase
( assertEqual
"C4 - comments - robust"
[]
$ parseFile " // a;b;c 123 "
"C4 - case 2. like 2020.1.1-2020.1.3 - a1 a3"
[(1, 4, "2020.1.1"), (2, 4, "2020.1.2"), (3, 4, "2020.1.3"), (4, 4, "2020.1.6")]
$ map (\(Date a b c) -> (a, b, printTime c))
$ parseDates "2020.1.1-2020.1.3,2020.1.6"
)
testC5 =
TestCase
( assertEqual
"C5 - hybrid - basic"
[["a", "b", "c"]]
$ parseFile "a;b;c // d;e;f 456 "
"C5 - case 2. like 2020.1.1-2020.1.3 - a3 a1"
[(1, 5, "2019.12.6"), (2, 5, "2020.1.1"), (3, 5, "2020.1.2"), (4, 5, "2020.1.3"), (5, 5, "2021.11.11")]
$ map (\(Date a b c) -> (a, b, printTime c))
$ parseDates "2019.12.6,2020.1.1-2020.1.3,2021.11.11"
)
testC6 =
TestCase
( assertEqual
"C6 - hybrid - robust"
[["a", "b", "c"]]
$ parseFile " a;b;c 123 // d;e;f 456 "
)
testC7 =
TestCase
( assertEqual
"C7 - empty - basic"
[]
$ parseFile ""
)
testC8 =
TestCase
( assertEqual
"C8 - empty - robust"
[]
$ parseFile " // "
)
testC9 =
TestCase
( assertEqual
"C9 - multi-line"
[["a", "b", "c"], ["d", "e", "f"]]
$ parseFile . unlines
$ [ "// INTRO",
"",
"a;b;c // dp1",
"// comment",
"d;e;f // dp2",
"END // TEST"
]
"C6 - case 2. like 2020.1.1-2020.1.3 - a3 a1"
[(1, 3, "2019.12.6"), (2, 3, "2020.1.1"), (3, 3, "2021.11.11")]
$ map (\(Date a b c) -> (a, b, printTime c))
$ parseDates "2019.12.6,2020.1.1-2020.1.1,,,2021.11.11"
)
tests :: Test
tests =
TestList
[ -- A. parseDate'
TestLabel "Test parseDate' 1" testA1,
TestLabel "Test parseDate' 2" testA2,
TestLabel "Test parseDate' 3" testA3,
TestLabel "Test parseDate' 4" testA4,
TestLabel "Test parseDate' 5" testA5,
TestLabel "Test parseDate' 6" testA6,
-- B. parseDate
TestLabel "Test parseDate 1" testB1,
TestLabel "Test parseDate 2" testB2,
TestLabel "Test parseDate 3" testB3,
TestLabel "Test parseDate 4" testB4,
TestLabel "Test parseDate 5" testB5,
-- C. parseFile
TestLabel "Test parseFile 1" testC1,
TestLabel "Test parseFile 2" testC2,
TestLabel "Test parseFile 3" testC3,
TestLabel "Test parseFile 4" testC4,
TestLabel "Test parseFile 5" testC5,
TestLabel "Test parseFile 6" testC6,
TestLabel "Test parseFile 7" testC7,
TestLabel "Test parseFile 8" testC8,
TestLabel "Test parseFile 9" testC9
[ -- A. parseRaw
TestLabel "Test parseRaw 1" testA1
, TestLabel "Test parseRaw 2" testA2
, TestLabel "Test parseRaw 3" testA3
, TestLabel "Test parseRaw 4" testA4
, TestLabel "Test parseRaw 5" testA5
, TestLabel "Test parseRaw 6" testA6
, TestLabel "Test parseRaw 7" testA7
, TestLabel "Test parseRaw 8" testA8
, TestLabel "Test parseRaw 9" testA9
, -- B. parseDate
TestLabel "Test parseDate 1" testB1
, TestLabel "Test parseDate 2" testB2
, TestLabel "Test parseDate 3" testB3
, TestLabel "Test parseDate 4" testB4
, TestLabel "Test parseDate 5" testB5
, TestLabel "Test parseDate 6" testB6
, -- C. parseDates
TestLabel "Test parseDates 1" testC1
, TestLabel "Test parseDates 2" testC2
, TestLabel "Test parseDates 3" testC3
, TestLabel "Test parseDates 4" testC4
, TestLabel "Test parseDates 5" testC5
, TestLabel "Test parseDates 6" testC6
]
main :: IO ()