hapilibur 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hapilibur-0.2.0/LICENSE +21 -0
- hapilibur-0.2.0/PKG-INFO +162 -0
- hapilibur-0.2.0/README.md +144 -0
- hapilibur-0.2.0/pyproject.toml +34 -0
- hapilibur-0.2.0/setup.cfg +4 -0
- hapilibur-0.2.0/src/hapilibur/__init__.py +25 -0
- hapilibur-0.2.0/src/hapilibur/__main__.py +151 -0
- hapilibur-0.2.0/src/hapilibur/core.py +279 -0
- hapilibur-0.2.0/src/hapilibur/data/cuti-bersama.json +29 -0
- hapilibur-0.2.0/src/hapilibur/data/jakarta-2026.json +313 -0
- hapilibur-0.2.0/src/hapilibur/data/libur-nasional.json +38 -0
- hapilibur-0.2.0/src/hapilibur/data/surabaya-2026.json +313 -0
- hapilibur-0.2.0/src/hapilibur/py.typed +0 -0
- hapilibur-0.2.0/src/hapilibur.egg-info/PKG-INFO +162 -0
- hapilibur-0.2.0/src/hapilibur.egg-info/SOURCES.txt +18 -0
- hapilibur-0.2.0/src/hapilibur.egg-info/dependency_links.txt +1 -0
- hapilibur-0.2.0/src/hapilibur.egg-info/entry_points.txt +2 -0
- hapilibur-0.2.0/src/hapilibur.egg-info/top_level.txt +1 -0
- hapilibur-0.2.0/tests/test_data_integrity.py +49 -0
- hapilibur-0.2.0/tests/test_hapilibur.py +125 -0
hapilibur-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aditya Purnama
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
hapilibur-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hapilibur
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Dataset & pustaka hari libur nasional, cuti bersama, dan jadwal imsakiyah Indonesia (2026). Data murni JSON, bebas dipakai lintas bahasa.
|
|
5
|
+
Author-email: Aditya Purnama <306090472+kiraadityaa@users.noreply.github.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/kiraadityaa/data-libur-nasional-indonesia
|
|
8
|
+
Project-URL: Repository, https://github.com/kiraadityaa/data-libur-nasional-indonesia
|
|
9
|
+
Keywords: indonesia,libur,holiday,cuti-bersama,imsakiyah,ramadhan,api,json
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
12
|
+
Classifier: Topic :: Utilities
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# data-libur-nasional-indonesia
|
|
20
|
+
|
|
21
|
+
Dataset dan REST API hari libur nasional, cuti bersama, dan jadwal imsakiyah Indonesia — 17 libur, 8 cuti bersama, 2 kota (2026). JSON murni, gratis, tanpa kunci API.
|
|
22
|
+
|
|
23
|
+
[](#pustaka-python)
|
|
24
|
+
[](https://github.com/kiraadityaa/data-libur-nasional-indonesia/actions)
|
|
25
|
+
[](#lisensi)
|
|
26
|
+
|
|
27
|
+
Live demo dan playground: <https://data-libur-nasional-indonesia.vercel.app> · Spesifikasi mesin-terbaca: [`/openapi.json`](https://data-libur-nasional-indonesia.vercel.app/openapi.json) · Contoh mentah: [`data/libur-nasional.json`](data/libur-nasional.json)
|
|
28
|
+
|
|
29
|
+
## Mulai dalam 30 detik
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# 1. Cek satu tanggal via API
|
|
33
|
+
curl "https://data-libur-nasional-indonesia.vercel.app/api/libur?date=2026-08-17"
|
|
34
|
+
|
|
35
|
+
# 2. Sama via pustaka Python (dari source repo ini)
|
|
36
|
+
pip install .
|
|
37
|
+
python -c "from hapilibur import is_libur; print(is_libur('2026-08-17'))" # True
|
|
38
|
+
|
|
39
|
+
# 3. Subscribe kalender tim ke Google/Apple Calendar
|
|
40
|
+
# https://data-libur-nasional-indonesia.vercel.app/api/libur.ics?year=2026
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Data mentah
|
|
44
|
+
|
|
45
|
+
Semua data adalah JSON statis tanpa framework — unduh dan parse dari bahasa apa pun.
|
|
46
|
+
|
|
47
|
+
<details>
|
|
48
|
+
<summary>Daftar file dataset</summary>
|
|
49
|
+
|
|
50
|
+
| File | Isi |
|
|
51
|
+
|------|-----|
|
|
52
|
+
| [`data/libur-nasional.json`](data/libur-nasional.json) | Hari libur nasional per tahun |
|
|
53
|
+
| [`data/cuti-bersama.json`](data/cuti-bersama.json) | Cuti bersama per tahun |
|
|
54
|
+
| [`data/imsak/jakarta-2026.json`](data/imsak/jakarta-2026.json) | Imsakiyah Jakarta (30 hari Ramadan 1447 H) |
|
|
55
|
+
| [`data/imsak/surabaya-2026.json`](data/imsak/surabaya-2026.json) | Imsakiyah Surabaya (30 hari Ramadan 1447 H) |
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
curl https://raw.githubusercontent.com/kiraadityaa/data-libur-nasional-indonesia/main/data/libur-nasional.json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
</details>
|
|
62
|
+
|
|
63
|
+
## REST API
|
|
64
|
+
|
|
65
|
+
Base URL: `https://data-libur-nasional-indonesia.vercel.app`. Semua endpoint `GET`, cache publik, mendukung preflight `OPTIONS`, dan mengembalikan error terstandar `{error, hint}`.
|
|
66
|
+
|
|
67
|
+
| Endpoint | Guna | Contoh |
|
|
68
|
+
|----------|------|--------|
|
|
69
|
+
| `/api/libur?date=YYYY-MM-DD` | Cek satu tanggal | `?date=2026-08-17` |
|
|
70
|
+
| `/api/libur?year=YYYY` | Rekap setahun (`libur_nasional`, `cuti_bersama`, total) | `?year=2026`, `&format=csv` untuk CSV |
|
|
71
|
+
| `/api/libur?year=YYYY&month=M` | Libur satu bulan | `?year=2026&month=3` |
|
|
72
|
+
| `/api/libur?next=1` | N libur berikutnya (`count` 1–30, default hari ini WIB) | `?next=1&date=2026-06-11&count=3` |
|
|
73
|
+
| `/api/libur?from=&to=` | Rentang tanggal inklusif | `?from=2026-03-20&to=2026-03-24` |
|
|
74
|
+
| `/api/imsak?city=` | Imsakiyah 30 hari (`imsak, subuh, zuhur, ashar, magrib, isya`) | `?city=jakarta&year=2026`, `&date=2026-03-01`, `&format=csv` |
|
|
75
|
+
| `/api/kota` | Daftar kota, provinsi, zona waktu, tahun tersedia | — |
|
|
76
|
+
| `/api/libur.ics` | Kalender iCalendar RFC 5545 | `?year=2026`, `?type=libur`, `?next=1&count=5` |
|
|
77
|
+
| `/api/health` | Health check | — |
|
|
78
|
+
|
|
79
|
+
Parameter `type=all|libur|cuti` berlaku untuk `/api/libur` dan `/api/libur.ics`. Dokumentasi lengkap ada di [`/openapi.json`](https://data-libur-nasional-indonesia.vercel.app/openapi.json) (live: `/api/openapi.json`).
|
|
80
|
+
|
|
81
|
+
Contoh respons:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
// GET /api/libur?date=2026-08-17
|
|
85
|
+
{
|
|
86
|
+
"date": "2026-08-17",
|
|
87
|
+
"is_holiday": true,
|
|
88
|
+
"libur_nasional": { "date": "2026-08-17", "name": "Hari Proklamasi Kemerdekaan RI" },
|
|
89
|
+
"cuti_bersama": null
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Google Calendar → Settings → Import & export
|
|
95
|
+
curl -o libur-indonesia.ics "https://data-libur-nasional-indonesia.vercel.app/api/libur.ics?year=2026"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Pustaka Python
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pip install .
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from hapilibur import check_detail, imsak, is_libur, month, upcoming
|
|
106
|
+
|
|
107
|
+
is_libur("2026-08-17") # True
|
|
108
|
+
is_libur("2026-03-23", include_cuti=False) # False — itu cuti bersama
|
|
109
|
+
check_detail("2026-08-17")
|
|
110
|
+
# {'date': '2026-08-17', 'name': 'Hari Proklamasi Kemerdekaan RI', 'jenis': ['libur_nasional']}
|
|
111
|
+
month(2026, 3) # 7 tanggal (libur + cuti)
|
|
112
|
+
upcoming("2026-06-11", n=3) # 3 libur terdekat
|
|
113
|
+
imsak("jakarta", 2026)["schedule"][0]
|
|
114
|
+
# {'day': 1, 'date': '2026-02-19', 'imsak': '04:31', 'subuh': '04:41', ...}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
<details>
|
|
118
|
+
<summary>Referensi CLI lengkap</summary>
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
hapilibur check 2026-08-17 # cek satu tanggal (tambah --json untuk detail)
|
|
122
|
+
hapilibur tahun 2026 [--json|--csv] # libur nasional setahun
|
|
123
|
+
hapilibur cuti 2026 [--json|--csv] # cuti bersama setahun
|
|
124
|
+
hapilibur bulan 2026 3 [--tanpa-cuti] # libur satu bulan
|
|
125
|
+
hapilibur selang 2026-01-01 2026-12-31 # rentang inklusif (alias: range)
|
|
126
|
+
hapilibur upcoming 2026-06-11 -n 3 # libur berikutnya (alias: next)
|
|
127
|
+
hapilibur imsak jakarta 2026 [--json] # imsakiyah satu kota
|
|
128
|
+
hapilibur kota # kota yang tersedia
|
|
129
|
+
hapilibur --version
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Error input (tanggal salah, kota tak dikenal) keluar sebagai satu baris `Error: ...` dengan exit code 2.
|
|
133
|
+
|
|
134
|
+
</details>
|
|
135
|
+
|
|
136
|
+
## English summary
|
|
137
|
+
|
|
138
|
+
Static JSON dataset and free REST API for Indonesian national holidays, collective leave (*cuti bersama*), and Ramadan prayer times (*imsakiyah*) for Jakarta and Surabaya. Sources: the tri-ministerial decree (SKB 3 Menteri) and the Ministry of Religious Affairs. No API key. Endpoints return JSON, CSV, or iCalendar; a Python library and CLI (`hapilibur`) ship in the same repo. See [Quickstart](#mulai-dalam-30-detik) for copy-paste examples and [`/openapi.json`](https://data-libur-nasional-indonesia.vercel.app/openapi.json) for the full spec.
|
|
139
|
+
|
|
140
|
+
## Pengembangan dan kontribusi
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npm run typecheck # tipe API TypeScript
|
|
144
|
+
npm run build:site # generate public/index.html + openapi.json + sitemap.xml + manifest
|
|
145
|
+
npm run validate # validasi data JSON
|
|
146
|
+
npm test # pytest
|
|
147
|
+
npm run verify # semua di atas, sekali jalan
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Menambah tahun baru:
|
|
151
|
+
|
|
152
|
+
1. Tambahkan data ke [`data/libur-nasional.json`](data/libur-nasional.json) dan [`data/cuti-bersama.json`](data/cuti-bersama.json).
|
|
153
|
+
2. `npm run validate` — wajib lolos.
|
|
154
|
+
3. `npm run build:site` agar halaman statis tersinkron.
|
|
155
|
+
4. `python3 -m pytest -q` dan `python3 scripts/generate.py` agar salinan di package tersinkron.
|
|
156
|
+
5. Buat pull request.
|
|
157
|
+
|
|
158
|
+
Sumber resmi: [SKB 3 Menteri 2026 (PDF)](https://www.kemenkopmk.go.id/sites/default/files/pengumuman/2025-09/SKB%20Libur%20Nasional%20dan%20Cuti%20Bersama%20Tahun%202026.pdf) · [Bimas Islam Kemenag](https://bimasislam.kemenag.go.id). Data mengikuti penetapan pemerintah dan bisa direvisi; awal Ramadan bisa bergeser ±1 hari karena Rukyatul Hilal; data 2027 ditambahkan setelah SKB resmi terbit.
|
|
159
|
+
|
|
160
|
+
## Lisensi
|
|
161
|
+
|
|
162
|
+
MIT — lihat [LICENSE](LICENSE). Data publik bersumber dari instansi pemerintah; atribusi tetap dicantumkan.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# data-libur-nasional-indonesia
|
|
2
|
+
|
|
3
|
+
Dataset dan REST API hari libur nasional, cuti bersama, dan jadwal imsakiyah Indonesia — 17 libur, 8 cuti bersama, 2 kota (2026). JSON murni, gratis, tanpa kunci API.
|
|
4
|
+
|
|
5
|
+
[](#pustaka-python)
|
|
6
|
+
[](https://github.com/kiraadityaa/data-libur-nasional-indonesia/actions)
|
|
7
|
+
[](#lisensi)
|
|
8
|
+
|
|
9
|
+
Live demo dan playground: <https://data-libur-nasional-indonesia.vercel.app> · Spesifikasi mesin-terbaca: [`/openapi.json`](https://data-libur-nasional-indonesia.vercel.app/openapi.json) · Contoh mentah: [`data/libur-nasional.json`](data/libur-nasional.json)
|
|
10
|
+
|
|
11
|
+
## Mulai dalam 30 detik
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# 1. Cek satu tanggal via API
|
|
15
|
+
curl "https://data-libur-nasional-indonesia.vercel.app/api/libur?date=2026-08-17"
|
|
16
|
+
|
|
17
|
+
# 2. Sama via pustaka Python (dari source repo ini)
|
|
18
|
+
pip install .
|
|
19
|
+
python -c "from hapilibur import is_libur; print(is_libur('2026-08-17'))" # True
|
|
20
|
+
|
|
21
|
+
# 3. Subscribe kalender tim ke Google/Apple Calendar
|
|
22
|
+
# https://data-libur-nasional-indonesia.vercel.app/api/libur.ics?year=2026
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Data mentah
|
|
26
|
+
|
|
27
|
+
Semua data adalah JSON statis tanpa framework — unduh dan parse dari bahasa apa pun.
|
|
28
|
+
|
|
29
|
+
<details>
|
|
30
|
+
<summary>Daftar file dataset</summary>
|
|
31
|
+
|
|
32
|
+
| File | Isi |
|
|
33
|
+
|------|-----|
|
|
34
|
+
| [`data/libur-nasional.json`](data/libur-nasional.json) | Hari libur nasional per tahun |
|
|
35
|
+
| [`data/cuti-bersama.json`](data/cuti-bersama.json) | Cuti bersama per tahun |
|
|
36
|
+
| [`data/imsak/jakarta-2026.json`](data/imsak/jakarta-2026.json) | Imsakiyah Jakarta (30 hari Ramadan 1447 H) |
|
|
37
|
+
| [`data/imsak/surabaya-2026.json`](data/imsak/surabaya-2026.json) | Imsakiyah Surabaya (30 hari Ramadan 1447 H) |
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
curl https://raw.githubusercontent.com/kiraadityaa/data-libur-nasional-indonesia/main/data/libur-nasional.json
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
</details>
|
|
44
|
+
|
|
45
|
+
## REST API
|
|
46
|
+
|
|
47
|
+
Base URL: `https://data-libur-nasional-indonesia.vercel.app`. Semua endpoint `GET`, cache publik, mendukung preflight `OPTIONS`, dan mengembalikan error terstandar `{error, hint}`.
|
|
48
|
+
|
|
49
|
+
| Endpoint | Guna | Contoh |
|
|
50
|
+
|----------|------|--------|
|
|
51
|
+
| `/api/libur?date=YYYY-MM-DD` | Cek satu tanggal | `?date=2026-08-17` |
|
|
52
|
+
| `/api/libur?year=YYYY` | Rekap setahun (`libur_nasional`, `cuti_bersama`, total) | `?year=2026`, `&format=csv` untuk CSV |
|
|
53
|
+
| `/api/libur?year=YYYY&month=M` | Libur satu bulan | `?year=2026&month=3` |
|
|
54
|
+
| `/api/libur?next=1` | N libur berikutnya (`count` 1–30, default hari ini WIB) | `?next=1&date=2026-06-11&count=3` |
|
|
55
|
+
| `/api/libur?from=&to=` | Rentang tanggal inklusif | `?from=2026-03-20&to=2026-03-24` |
|
|
56
|
+
| `/api/imsak?city=` | Imsakiyah 30 hari (`imsak, subuh, zuhur, ashar, magrib, isya`) | `?city=jakarta&year=2026`, `&date=2026-03-01`, `&format=csv` |
|
|
57
|
+
| `/api/kota` | Daftar kota, provinsi, zona waktu, tahun tersedia | — |
|
|
58
|
+
| `/api/libur.ics` | Kalender iCalendar RFC 5545 | `?year=2026`, `?type=libur`, `?next=1&count=5` |
|
|
59
|
+
| `/api/health` | Health check | — |
|
|
60
|
+
|
|
61
|
+
Parameter `type=all|libur|cuti` berlaku untuk `/api/libur` dan `/api/libur.ics`. Dokumentasi lengkap ada di [`/openapi.json`](https://data-libur-nasional-indonesia.vercel.app/openapi.json) (live: `/api/openapi.json`).
|
|
62
|
+
|
|
63
|
+
Contoh respons:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
// GET /api/libur?date=2026-08-17
|
|
67
|
+
{
|
|
68
|
+
"date": "2026-08-17",
|
|
69
|
+
"is_holiday": true,
|
|
70
|
+
"libur_nasional": { "date": "2026-08-17", "name": "Hari Proklamasi Kemerdekaan RI" },
|
|
71
|
+
"cuti_bersama": null
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Google Calendar → Settings → Import & export
|
|
77
|
+
curl -o libur-indonesia.ics "https://data-libur-nasional-indonesia.vercel.app/api/libur.ics?year=2026"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Pustaka Python
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pip install .
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from hapilibur import check_detail, imsak, is_libur, month, upcoming
|
|
88
|
+
|
|
89
|
+
is_libur("2026-08-17") # True
|
|
90
|
+
is_libur("2026-03-23", include_cuti=False) # False — itu cuti bersama
|
|
91
|
+
check_detail("2026-08-17")
|
|
92
|
+
# {'date': '2026-08-17', 'name': 'Hari Proklamasi Kemerdekaan RI', 'jenis': ['libur_nasional']}
|
|
93
|
+
month(2026, 3) # 7 tanggal (libur + cuti)
|
|
94
|
+
upcoming("2026-06-11", n=3) # 3 libur terdekat
|
|
95
|
+
imsak("jakarta", 2026)["schedule"][0]
|
|
96
|
+
# {'day': 1, 'date': '2026-02-19', 'imsak': '04:31', 'subuh': '04:41', ...}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
<details>
|
|
100
|
+
<summary>Referensi CLI lengkap</summary>
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
hapilibur check 2026-08-17 # cek satu tanggal (tambah --json untuk detail)
|
|
104
|
+
hapilibur tahun 2026 [--json|--csv] # libur nasional setahun
|
|
105
|
+
hapilibur cuti 2026 [--json|--csv] # cuti bersama setahun
|
|
106
|
+
hapilibur bulan 2026 3 [--tanpa-cuti] # libur satu bulan
|
|
107
|
+
hapilibur selang 2026-01-01 2026-12-31 # rentang inklusif (alias: range)
|
|
108
|
+
hapilibur upcoming 2026-06-11 -n 3 # libur berikutnya (alias: next)
|
|
109
|
+
hapilibur imsak jakarta 2026 [--json] # imsakiyah satu kota
|
|
110
|
+
hapilibur kota # kota yang tersedia
|
|
111
|
+
hapilibur --version
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Error input (tanggal salah, kota tak dikenal) keluar sebagai satu baris `Error: ...` dengan exit code 2.
|
|
115
|
+
|
|
116
|
+
</details>
|
|
117
|
+
|
|
118
|
+
## English summary
|
|
119
|
+
|
|
120
|
+
Static JSON dataset and free REST API for Indonesian national holidays, collective leave (*cuti bersama*), and Ramadan prayer times (*imsakiyah*) for Jakarta and Surabaya. Sources: the tri-ministerial decree (SKB 3 Menteri) and the Ministry of Religious Affairs. No API key. Endpoints return JSON, CSV, or iCalendar; a Python library and CLI (`hapilibur`) ship in the same repo. See [Quickstart](#mulai-dalam-30-detik) for copy-paste examples and [`/openapi.json`](https://data-libur-nasional-indonesia.vercel.app/openapi.json) for the full spec.
|
|
121
|
+
|
|
122
|
+
## Pengembangan dan kontribusi
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
npm run typecheck # tipe API TypeScript
|
|
126
|
+
npm run build:site # generate public/index.html + openapi.json + sitemap.xml + manifest
|
|
127
|
+
npm run validate # validasi data JSON
|
|
128
|
+
npm test # pytest
|
|
129
|
+
npm run verify # semua di atas, sekali jalan
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Menambah tahun baru:
|
|
133
|
+
|
|
134
|
+
1. Tambahkan data ke [`data/libur-nasional.json`](data/libur-nasional.json) dan [`data/cuti-bersama.json`](data/cuti-bersama.json).
|
|
135
|
+
2. `npm run validate` — wajib lolos.
|
|
136
|
+
3. `npm run build:site` agar halaman statis tersinkron.
|
|
137
|
+
4. `python3 -m pytest -q` dan `python3 scripts/generate.py` agar salinan di package tersinkron.
|
|
138
|
+
5. Buat pull request.
|
|
139
|
+
|
|
140
|
+
Sumber resmi: [SKB 3 Menteri 2026 (PDF)](https://www.kemenkopmk.go.id/sites/default/files/pengumuman/2025-09/SKB%20Libur%20Nasional%20dan%20Cuti%20Bersama%20Tahun%202026.pdf) · [Bimas Islam Kemenag](https://bimasislam.kemenag.go.id). Data mengikuti penetapan pemerintah dan bisa direvisi; awal Ramadan bisa bergeser ±1 hari karena Rukyatul Hilal; data 2027 ditambahkan setelah SKB resmi terbit.
|
|
141
|
+
|
|
142
|
+
## Lisensi
|
|
143
|
+
|
|
144
|
+
MIT — lihat [LICENSE](LICENSE). Data publik bersumber dari instansi pemerintah; atribusi tetap dicantumkan.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hapilibur"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "Dataset & pustaka hari libur nasional, cuti bersama, dan jadwal imsakiyah Indonesia (2026). Data murni JSON, bebas dipakai lintas bahasa."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Aditya Purnama", email = "306090472+kiraadityaa@users.noreply.github.com" }]
|
|
13
|
+
keywords = ["indonesia", "libur", "holiday", "cuti-bersama", "imsakiyah", "ramadhan", "api", "json"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
17
|
+
"Topic :: Utilities",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
]
|
|
20
|
+
dependencies = []
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://github.com/kiraadityaa/data-libur-nasional-indonesia"
|
|
24
|
+
Repository = "https://github.com/kiraadityaa/data-libur-nasional-indonesia"
|
|
25
|
+
|
|
26
|
+
[project.scripts]
|
|
27
|
+
hapilibur = "hapilibur.__main__:main"
|
|
28
|
+
|
|
29
|
+
[tool.setuptools]
|
|
30
|
+
package-dir = { "" = "src" }
|
|
31
|
+
packages = ["hapilibur"]
|
|
32
|
+
|
|
33
|
+
[tool.setuptools.package-data]
|
|
34
|
+
hapilibur = ["data/*.json", "py.typed"]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""hapilibur — dataset & bantu hitung hari libur nasional dan cuti bersama Indonesia.
|
|
2
|
+
|
|
3
|
+
Sumber: SKB 3 Menteri (Hari Libur Nasional & Cuti Bersama) dan Imsakiyah Bimas Islam Kemenag.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .core import ( # noqa: F401
|
|
7
|
+
CUTI_FILE,
|
|
8
|
+
LIBUR_FILE,
|
|
9
|
+
available_cities,
|
|
10
|
+
between,
|
|
11
|
+
check,
|
|
12
|
+
check_detail,
|
|
13
|
+
cuti,
|
|
14
|
+
holiday_range,
|
|
15
|
+
imsak,
|
|
16
|
+
imsak_cities_available,
|
|
17
|
+
is_holiday,
|
|
18
|
+
is_libur,
|
|
19
|
+
libur,
|
|
20
|
+
month,
|
|
21
|
+
to_csv,
|
|
22
|
+
upcoming,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
__version__ = "0.2.0"
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""CLI hapilibur: cek hari libur, cuti bersama, dan jadwal imsakiyah dari terminal."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import datetime
|
|
6
|
+
import json
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
from . import __version__, core
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _emit(entries: list[dict] | dict, as_json: bool, as_csv: bool) -> None:
|
|
13
|
+
if as_json:
|
|
14
|
+
print(json.dumps(entries, ensure_ascii=False, indent=2))
|
|
15
|
+
return
|
|
16
|
+
if as_csv:
|
|
17
|
+
items = entries if isinstance(entries, list) else [entries]
|
|
18
|
+
print(core.to_csv([e for e in items if e.get("date")]), end="")
|
|
19
|
+
return
|
|
20
|
+
if isinstance(entries, dict):
|
|
21
|
+
print(f"{entries.get('date')} {entries.get('name')}")
|
|
22
|
+
return
|
|
23
|
+
for entry in entries:
|
|
24
|
+
print(f"{entry['date']} {entry['name']}")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _fmt_date(value: str, as_json: bool) -> None:
|
|
28
|
+
detail = core.check_detail(value)
|
|
29
|
+
if as_json:
|
|
30
|
+
print(json.dumps(detail or {"date": value, "is_holiday": False}, ensure_ascii=False, indent=2))
|
|
31
|
+
return
|
|
32
|
+
print(f"{value}: {detail['name'] if detail else 'Bukan hari libur nasional / cuti bersama'}")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _print_holidays(entries: list[dict], year: int | None, as_json: bool, as_csv: bool) -> None:
|
|
36
|
+
if not entries:
|
|
37
|
+
label = f"tahun {year}" if year else "rentang tersebut"
|
|
38
|
+
if as_json:
|
|
39
|
+
print("[]")
|
|
40
|
+
elif not as_csv:
|
|
41
|
+
print(f"Tidak ada data untuk {label}.")
|
|
42
|
+
else:
|
|
43
|
+
print("tanggal,nama")
|
|
44
|
+
return
|
|
45
|
+
_emit(entries, as_json, as_csv)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _print_imsak(payload: dict, as_json: bool) -> None:
|
|
49
|
+
if as_json:
|
|
50
|
+
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
51
|
+
return
|
|
52
|
+
print(f"{payload['title']} ({payload['timezone']})")
|
|
53
|
+
print(f"{'Hari':<5}{'Tanggal':<12}{'Imsak':<7}{'Subuh':<7}{'Zuhur':<7}{'Ashar':<7}{'Magrib':<7}{'Isya':<7}")
|
|
54
|
+
for item in payload["schedule"]:
|
|
55
|
+
print(
|
|
56
|
+
f"{item['day']:<5}{item['date']:<12}{item['imsak']:<7}{item['subuh']:<7}"
|
|
57
|
+
f"{item['zuhur']:<7}{item['ashar']:<7}{item['magrib']:<7}{item['isya']:<7}"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _add_output_flags(parser: argparse.ArgumentParser) -> None:
|
|
62
|
+
parser.add_argument("--json", action="store_true", help="keluarkan sebagai JSON")
|
|
63
|
+
parser.add_argument("--csv", action="store_true", help="keluarkan sebagai CSV")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
67
|
+
parser = argparse.ArgumentParser(
|
|
68
|
+
prog="hapilibur",
|
|
69
|
+
description="Cek hari libur nasional, cuti bersama, dan jadwal imsakiyah Indonesia.",
|
|
70
|
+
)
|
|
71
|
+
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
|
|
72
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
73
|
+
|
|
74
|
+
p_check = sub.add_parser("check", help="cek apakah suatu tanggal hari libur")
|
|
75
|
+
p_check.add_argument("tanggal", help="tanggal dalam format YYYY-MM-DD, misal 2026-08-17")
|
|
76
|
+
p_check.add_argument("--json", action="store_true", help="keluarkan sebagai JSON")
|
|
77
|
+
|
|
78
|
+
p_tahun = sub.add_parser("tahun", help="daftar hari libur nasional satu tahun")
|
|
79
|
+
p_tahun.add_argument("tahun", nargs="?", type=int, help="tahun (default: tahun berjalan)")
|
|
80
|
+
_add_output_flags(p_tahun)
|
|
81
|
+
|
|
82
|
+
p_cuti = sub.add_parser("cuti", help="daftar cuti bersama satu tahun")
|
|
83
|
+
p_cuti.add_argument("tahun", nargs="?", type=int, help="tahun (default: tahun berjalan)")
|
|
84
|
+
_add_output_flags(p_cuti)
|
|
85
|
+
|
|
86
|
+
p_bulan = sub.add_parser("bulan", help="daftar tanggal libur satu bulan")
|
|
87
|
+
p_bulan.add_argument("tahun", type=int, help="tahun, misal 2026")
|
|
88
|
+
p_bulan.add_argument("bulan", type=int, help="bulan 1-12, misal 3")
|
|
89
|
+
p_bulan.add_argument("--tanpa-cuti", action="store_true", help="kecualikan cuti bersama")
|
|
90
|
+
_add_output_flags(p_bulan)
|
|
91
|
+
|
|
92
|
+
p_selang = sub.add_parser("selang", help="daftar tanggal libur dalam rentang tanggal", aliases=["range"])
|
|
93
|
+
p_selang.add_argument("dari", help="tanggal awal YYYY-MM-DD")
|
|
94
|
+
p_selang.add_argument("sampai", help="tanggal akhir YYYY-MM-DD")
|
|
95
|
+
_add_output_flags(p_selang)
|
|
96
|
+
|
|
97
|
+
p_next = sub.add_parser("upcoming", help="hari libur berikutnya", aliases=["next"])
|
|
98
|
+
p_next.add_argument("tanggal", nargs="?", help="awal pencarian (default: hari ini)")
|
|
99
|
+
p_next.add_argument("-n", "--count", type=int, default=1, help="jumlah hari libur (default: 1)")
|
|
100
|
+
p_next.add_argument("--json", action="store_true", help="keluarkan sebagai JSON")
|
|
101
|
+
|
|
102
|
+
p_imsak = sub.add_parser("imsak", help="jadwal imsakiyah sebuah kota")
|
|
103
|
+
p_imsak.add_argument("kota", help="nama kota, misal jakarta atau surabaya")
|
|
104
|
+
p_imsak.add_argument("tahun", nargs="?", type=int, help="tahun (default: tahun berjalan)")
|
|
105
|
+
p_imsak.add_argument("--json", action="store_true", help="keluarkan sebagai JSON")
|
|
106
|
+
|
|
107
|
+
sub.add_parser("kota", help="daftar kota yang tersedia")
|
|
108
|
+
|
|
109
|
+
return parser
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def main(argv: list[str] | None = None) -> int:
|
|
113
|
+
args = _build_parser().parse_args(argv)
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
if args.command == "check":
|
|
117
|
+
_fmt_date(args.tanggal, as_json=args.json)
|
|
118
|
+
elif args.command == "tahun":
|
|
119
|
+
year = args.tahun or datetime.date.today().year
|
|
120
|
+
_print_holidays(core.libur(year), year, args.json, args.csv)
|
|
121
|
+
elif args.command == "cuti":
|
|
122
|
+
year = args.tahun or datetime.date.today().year
|
|
123
|
+
_print_holidays(core.cuti(year), year, args.json, args.csv)
|
|
124
|
+
elif args.command == "bulan":
|
|
125
|
+
entries = core.month(args.tahun, args.bulan, include_cuti=not args.tanpa_cuti)
|
|
126
|
+
_print_holidays(entries, args.tahun, args.json, args.csv)
|
|
127
|
+
elif args.command in ("selang", "range"):
|
|
128
|
+
_print_holidays(core.between(args.dari, args.sampai), None, args.json, args.csv)
|
|
129
|
+
elif args.command in ("upcoming", "next"):
|
|
130
|
+
result = core.upcoming(args.tanggal, n=args.count)
|
|
131
|
+
if args.json:
|
|
132
|
+
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
133
|
+
elif args.count == 1:
|
|
134
|
+
assert isinstance(result, dict)
|
|
135
|
+
print(f"{result['date']} {result['name']}")
|
|
136
|
+
else:
|
|
137
|
+
assert isinstance(result, list)
|
|
138
|
+
for item in result:
|
|
139
|
+
print(f"{item['date']} {item['name']}")
|
|
140
|
+
elif args.command == "imsak":
|
|
141
|
+
_print_imsak(core.imsak(args.kota, args.tahun), as_json=args.json)
|
|
142
|
+
elif args.command == "kota":
|
|
143
|
+
print(", ".join(core.available_cities()))
|
|
144
|
+
except ValueError as exc:
|
|
145
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
146
|
+
return 2
|
|
147
|
+
return 0
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
if __name__ == "__main__":
|
|
151
|
+
sys.exit(main())
|