fcalendar 0.12.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.
- fcalendar-0.12.0/.github/workflows/publish.yml +35 -0
- fcalendar-0.12.0/.gitignore +10 -0
- fcalendar-0.12.0/.pylintrc +27 -0
- fcalendar-0.12.0/.python-version +1 -0
- fcalendar-0.12.0/.vscode/settings.json +7 -0
- fcalendar-0.12.0/LICENSE +21 -0
- fcalendar-0.12.0/MANIFEST.in +6 -0
- fcalendar-0.12.0/PKG-INFO +486 -0
- fcalendar-0.12.0/README.md +476 -0
- fcalendar-0.12.0/README_CN.md +529 -0
- fcalendar-0.12.0/fcalendar/__init__.py +84 -0
- fcalendar-0.12.0/fcalendar/cli.py +134 -0
- fcalendar-0.12.0/fcalendar/core.py +2092 -0
- fcalendar-0.12.0/fcalendar/py.typed +0 -0
- fcalendar-0.12.0/pyproject.toml +28 -0
- fcalendar-0.12.0/setup.py +57 -0
- fcalendar-0.12.0/tests/__init__.py +1 -0
- fcalendar-0.12.0/tests/benchmark.json +1486 -0
- fcalendar-0.12.0/tests/test_benchmark.py +640 -0
- fcalendar-0.12.0/tests/test_english.py +161 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
name: Build and publish to PyPI
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout repository
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.10"
|
|
23
|
+
|
|
24
|
+
- name: Install build dependencies
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install build
|
|
28
|
+
|
|
29
|
+
- name: Build package
|
|
30
|
+
run: python -m build
|
|
31
|
+
|
|
32
|
+
- name: Publish to PyPI
|
|
33
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
34
|
+
with:
|
|
35
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[MAIN]
|
|
2
|
+
# 忽略的模块
|
|
3
|
+
ignore=tests
|
|
4
|
+
|
|
5
|
+
[MESSAGES CONTROL]
|
|
6
|
+
# 禁用一些过于严格的检查
|
|
7
|
+
disable=
|
|
8
|
+
too-many-lines,
|
|
9
|
+
too-many-locals,
|
|
10
|
+
too-many-branches,
|
|
11
|
+
too-many-statements,
|
|
12
|
+
too-many-return-statements,
|
|
13
|
+
invalid-name,
|
|
14
|
+
broad-exception-caught,
|
|
15
|
+
consider-iterating-dictionary,
|
|
16
|
+
f-string-without-interpolation,
|
|
17
|
+
no-else-return,
|
|
18
|
+
import-outside-toplevel,
|
|
19
|
+
unused-variable,
|
|
20
|
+
redefined-outer-name,
|
|
21
|
+
reimported,
|
|
22
|
+
ungrouped-imports,
|
|
23
|
+
superfluous-parens
|
|
24
|
+
|
|
25
|
+
[FORMAT]
|
|
26
|
+
# 允许更长的行
|
|
27
|
+
max-line-length=120
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.10
|
fcalendar-0.12.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 youngfree
|
|
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.
|
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fcalendar
|
|
3
|
+
Version: 0.12.0
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Requires-Dist: chinesecalendar>=1.9.0
|
|
8
|
+
Requires-Dist: lunardate>=0.2.2
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
English | [简体中文](README_CN.md)
|
|
12
|
+
|
|
13
|
+
# fcalendar
|
|
14
|
+
|
|
15
|
+
A powerful Python library and CLI tool for recognizing and annotating Chinese/English time expressions, and querying Chinese public holiday schedules.
|
|
16
|
+
|
|
17
|
+
## ✨ Features
|
|
18
|
+
|
|
19
|
+
- 🌍 **Multi-language Support**: Automatic language detection, supports both Chinese and English input/output
|
|
20
|
+
- 🎯 **Relative Time**: tomorrow, next week, next month, etc.
|
|
21
|
+
- 📅 **Chinese Legal Holidays**: Spring Festival, National Day, Mid-Autumn Festival, etc.
|
|
22
|
+
- 🌙 **Lunar Calendar**: Traditional festivals, lunar dates
|
|
23
|
+
- 🎄 **Western Festivals**: Christmas, Halloween, Valentine's Day, etc.
|
|
24
|
+
- 🌸 **24 Solar Terms**: Spring Equinox, Winter Solstice, etc.
|
|
25
|
+
- 🍂 **Seasons**: Spring, Summer, Autumn, Winter
|
|
26
|
+
- 📊 **Quarters and Cycles**: Q1-Q4, first/second half of year
|
|
27
|
+
- 📆 **Specific Dates**: Supports various date formats
|
|
28
|
+
- 🔄 **Year Prefixes**: last year, next year, 2024, etc.
|
|
29
|
+
- ⏰ **Real-time**: Supports current time queries (returns Beijing time)
|
|
30
|
+
- 🗓️ **Holiday Query**: Query Chinese public holidays and weekends within a specified range
|
|
31
|
+
- 💻 **CLI Support**: All core features accessible via command-line interface
|
|
32
|
+
|
|
33
|
+
## 📦 Installation
|
|
34
|
+
|
|
35
|
+
### Install from PyPI
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install fcalendar
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Install from Aliyun PyPI (Internal Network)
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install fcalendar
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Install from Source
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
git clone https://github.com/youngfreefjs/fcalendar.git
|
|
51
|
+
cd fcalendar
|
|
52
|
+
pip install -e .
|
|
53
|
+
```
|
|
54
|
+
## 🚀 Quick Start
|
|
55
|
+
|
|
56
|
+
### Python API
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from fcalendar import query, holiday
|
|
60
|
+
import datetime
|
|
61
|
+
|
|
62
|
+
# Time expression recognition
|
|
63
|
+
result = query("meeting tomorrow", datetime.date(2026, 2, 13))
|
|
64
|
+
print(result)
|
|
65
|
+
# Output: meeting tomorrow (Today is February 13, 2026, tomorrow is February 14, 2026)
|
|
66
|
+
|
|
67
|
+
# Holiday query
|
|
68
|
+
result = holiday("next_month", datetime.date(2026, 3, 31))
|
|
69
|
+
print(result)
|
|
70
|
+
# Output: [{'type': 'holiday', 'name': '清明节', 'start': '2026-04-04', 'end': '2026-04-06', 'days': 3}, ...]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### CLI
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Time expression recognition
|
|
77
|
+
fcalendar query "meeting next Monday"
|
|
78
|
+
# Output: {"input": "meeting next Monday", "result": "meeting next Monday (Today is ..., next Monday is April 6, 2026)"}
|
|
79
|
+
|
|
80
|
+
# Holiday query (supports Chinese and English scope)
|
|
81
|
+
fcalendar holiday --scope next_month
|
|
82
|
+
fcalendar holiday --scope 本周
|
|
83
|
+
fcalendar holiday --scope "weeks=3"
|
|
84
|
+
fcalendar holiday --scope 未来两个月
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 🌍 Language Support
|
|
88
|
+
|
|
89
|
+
fcalendar supports both **Chinese** and **English** with automatic language detection:
|
|
90
|
+
|
|
91
|
+
### Automatic Language Detection
|
|
92
|
+
|
|
93
|
+
The library automatically detects the input language and returns output in the same language:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
# Chinese input → Chinese output
|
|
97
|
+
query("明天开会", datetime.date(2026, 2, 13))
|
|
98
|
+
# Output: 明天开会(今天是2026 年 2 月 13 日,明天是2026 年 2 月 14 日)
|
|
99
|
+
|
|
100
|
+
# English input → English output
|
|
101
|
+
query("meeting tomorrow", datetime.date(2026, 2, 13))
|
|
102
|
+
# Output: meeting tomorrow (Today is February 13, 2026, tomorrow is February 14, 2026)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Manual Language Specification
|
|
106
|
+
|
|
107
|
+
You can also manually specify the language using the `lang` parameter:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
# Force English output
|
|
111
|
+
query("tomorrow", datetime.date(2026, 2, 13), lang='en')
|
|
112
|
+
# Output: tomorrow (Today is February 13, 2026, tomorrow is February 14, 2026)
|
|
113
|
+
|
|
114
|
+
# Force Chinese output
|
|
115
|
+
query("明天", datetime.date(2026, 2, 13), lang='zh')
|
|
116
|
+
# Output: 明天(今天是2026 年 2 月 13 日,明天是2026 年 2 月 14 日)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Supported English Expressions
|
|
120
|
+
|
|
121
|
+
- **Relative time**: today, tomorrow, day after tomorrow, next week, next month
|
|
122
|
+
- **Weekdays**: Monday, Tuesday, next Monday, this weekend, next weekend
|
|
123
|
+
- **Festivals**: Christmas, Halloween, Valentine's Day, Easter, Thanksgiving
|
|
124
|
+
- **Specific dates**: January 15, 2026, July 15th, Jan 15
|
|
125
|
+
|
|
126
|
+
> **Note**: For Chinese documentation and examples, please see [README_CN.md](README_CN.md)
|
|
127
|
+
|
|
128
|
+
## 📖 Usage Examples
|
|
129
|
+
### Real-time Query
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
# Query current time (returns Beijing time)
|
|
133
|
+
result = query("现在是几点")
|
|
134
|
+
print(result)
|
|
135
|
+
# Output: 现在是几点(今天是2026 年 3 月 24 日,现在是2026 年 3 月 24 日 21:35:42)
|
|
136
|
+
|
|
137
|
+
# Supports various current time keywords
|
|
138
|
+
keywords = ["当前时间", "现在", "当前", "目前", "此时", "此刻", "眼下", "当下", "这会儿", "这时候", "今天"]
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## 📖 Supported Time Expressions
|
|
142
|
+
### 1️⃣ Relative Time and Real-time
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
# Relative time
|
|
146
|
+
query("meeting tomorrow", datetime.date(2026, 2, 13))
|
|
147
|
+
# Output: meeting tomorrow (Today is February 13, 2026, tomorrow is February 14, 2026)
|
|
148
|
+
|
|
149
|
+
query("travel day after tomorrow", datetime.date(2026, 2, 13))
|
|
150
|
+
# Output: travel day after tomorrow (Today is February 13, 2026, day after tomorrow is February 15, 2026)
|
|
151
|
+
|
|
152
|
+
query("appointment next week", datetime.date(2026, 2, 13))
|
|
153
|
+
# Output: appointment next week (Today is February 13, 2026, next week is February 20, 2026)
|
|
154
|
+
|
|
155
|
+
query("meeting next Monday", datetime.date(2026, 2, 13))
|
|
156
|
+
# Output: meeting next Monday (Today is February 13, 2026, next Monday is February 16, 2026)
|
|
157
|
+
|
|
158
|
+
query("travel next weekend", datetime.date(2026, 2, 13))
|
|
159
|
+
# Output: travel next weekend (Today is February 13, 2026, next weekend is February 21, 2026 - February 22, 2026)
|
|
160
|
+
|
|
161
|
+
query("party this weekend", datetime.date(2026, 2, 13))
|
|
162
|
+
# Output: party this weekend (Today is February 13, 2026, this weekend is February 14, 2026 - February 15, 2026)
|
|
163
|
+
|
|
164
|
+
query("visit museum Wednesday", datetime.date(2026, 2, 13))
|
|
165
|
+
# Output: visit museum Wednesday (Today is February 13, 2026, Wednesday is February 18, 2026)
|
|
166
|
+
|
|
167
|
+
query("business trip next month", datetime.date(2026, 2, 13))
|
|
168
|
+
# Output: business trip next month (Today is February 13, 2026, next month is March 1, 2026 - March 31, 2026)
|
|
169
|
+
|
|
170
|
+
# Real-time keywords (returns Beijing time)
|
|
171
|
+
query("what time is it now", datetime.date(2026, 2, 13))
|
|
172
|
+
# Output: what time is it now (Today is February 13, 2026, now is Beijing time February 13, 2026 00:00:00)
|
|
173
|
+
|
|
174
|
+
query("current time", datetime.date(2026, 2, 13))
|
|
175
|
+
# Output: current time (Today is February 13, 2026, current time is Beijing time February 13, 2026 00:00:00)
|
|
176
|
+
```
|
|
177
|
+
### 2️⃣ Western Festivals
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
query("buy gifts for Christmas", datetime.date(2026, 2, 13))
|
|
181
|
+
# Output: buy gifts for Christmas (Today is February 13, 2026, Christmas is December 25, 2026)
|
|
182
|
+
|
|
183
|
+
query("Halloween party", datetime.date(2026, 2, 13))
|
|
184
|
+
# Output: Halloween party (Today is February 13, 2026, Halloween is October 31, 2026)
|
|
185
|
+
|
|
186
|
+
query("Valentine's Day flowers", datetime.date(2026, 2, 13))
|
|
187
|
+
# Output: Valentine's Day flowers (Today is February 13, 2026, Valentine's Day is February 14, 2026)
|
|
188
|
+
|
|
189
|
+
query("Easter church service", datetime.date(2026, 2, 13))
|
|
190
|
+
# Output: Easter church service (Today is February 13, 2026, Easter is April 5, 2026)
|
|
191
|
+
|
|
192
|
+
query("Thanksgiving dinner", datetime.date(2026, 2, 13))
|
|
193
|
+
# Output: Thanksgiving dinner (Today is February 13, 2026, Thanksgiving is November 26, 2026)
|
|
194
|
+
|
|
195
|
+
query("Independence Day fireworks", datetime.date(2026, 2, 13))
|
|
196
|
+
# Output: Independence Day fireworks (Today is February 13, 2026, Independence Day is July 4, 2026)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### 3️⃣ Specific Dates
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
# Month and day
|
|
203
|
+
query("meeting on January 15", datetime.date(2026, 2, 13))
|
|
204
|
+
# Output: meeting on January 15 (Today is February 13, 2026, January 15 is January 15, 2027)
|
|
205
|
+
|
|
206
|
+
query("vacation July 15th", datetime.date(2026, 2, 13))
|
|
207
|
+
# Output: vacation July 15th (Today is February 13, 2026, July 15th is July 15, 2026)
|
|
208
|
+
|
|
209
|
+
# With year
|
|
210
|
+
query("conference on January 15, 2027", datetime.date(2026, 2, 13))
|
|
211
|
+
# Output: conference on January 15, 2027 (Today is February 13, 2026, January 15, 2027 is January 15, 2027)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### 4️⃣ Quarters and Cycles
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
query("Q1 meeting", datetime.date(2026, 2, 13))
|
|
218
|
+
# Output: Q1 meeting (Today is February 13, 2026, Q1 is January 1, 2026 - March 31, 2026)
|
|
219
|
+
|
|
220
|
+
query("Q4 summary", datetime.date(2026, 2, 13))
|
|
221
|
+
# Output: Q4 summary (Today is February 13, 2026, Q4 is October 1, 2026 - December 31, 2026)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### 5️⃣ Complex Combined Examples
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
# Multiple time expressions
|
|
228
|
+
text = "meeting tomorrow, travel next weekend, Christmas party"
|
|
229
|
+
result = query(text, datetime.date(2026, 2, 13))
|
|
230
|
+
print(result)
|
|
231
|
+
# Output: meeting tomorrow, travel next weekend, Christmas party (Today is February 13, 2026, tomorrow is February 14, 2026, next weekend is February 21, 2026 - February 22, 2026, Christmas is December 25, 2026)
|
|
232
|
+
|
|
233
|
+
# Comprehensive example
|
|
234
|
+
text = "meeting tomorrow, hotel reservation on July 15th, travel next weekend, visit museum Wednesday, buy gifts for Christmas, Q4 meeting, Easter church service"
|
|
235
|
+
result = query(text, datetime.date(2026, 2, 13))
|
|
236
|
+
# All time expressions will be correctly recognized and annotated
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## 🗓️ Holiday Query API
|
|
240
|
+
|
|
241
|
+
`holiday(scope, today)` queries Chinese public holidays and normal weekends within a given time range. Workdays-on-weekends (调休上班) are excluded to keep the output clean.
|
|
242
|
+
|
|
243
|
+
```python
|
|
244
|
+
from fcalendar import holiday
|
|
245
|
+
import datetime
|
|
246
|
+
|
|
247
|
+
# Next month's holidays
|
|
248
|
+
result = holiday("next_month", datetime.date(2026, 3, 31))
|
|
249
|
+
# [{'type': 'holiday', 'name': '清明节', 'start': '2026-04-04', 'end': '2026-04-06', 'days': 3},
|
|
250
|
+
# {'type': 'weekend', 'name': '周末', 'start': '2026-04-11', 'end': '2026-04-12', 'days': 2}, ...]
|
|
251
|
+
|
|
252
|
+
# This week
|
|
253
|
+
holiday("this_week")
|
|
254
|
+
holiday("本周") # Chinese scope also supported
|
|
255
|
+
|
|
256
|
+
# Next 3 weeks / 2 months
|
|
257
|
+
holiday("weeks=3")
|
|
258
|
+
holiday("三周") # Chinese numeral
|
|
259
|
+
holiday("months=2")
|
|
260
|
+
holiday("未来两个月")
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Return fields per record:**
|
|
264
|
+
|
|
265
|
+
| Field | Type | Description |
|
|
266
|
+
|-------|------|-------------|
|
|
267
|
+
| `type` | str | `"holiday"` (public holiday) or `"weekend"` (normal restful weekend) |
|
|
268
|
+
| `name` | str | Name, e.g. `"劳动节"`, `"周末"` |
|
|
269
|
+
| `start` | str | Start date, ISO format (YYYY-MM-DD) |
|
|
270
|
+
| `end` | str | End date, ISO format (YYYY-MM-DD) |
|
|
271
|
+
| `days` | int | Number of days |
|
|
272
|
+
|
|
273
|
+
**Supported scope values:**
|
|
274
|
+
|
|
275
|
+
| Scope | Alias | Description |
|
|
276
|
+
|-------|-------|-------------|
|
|
277
|
+
| `half_year` | `半年`, `未来半年` | Next 180 days (default) |
|
|
278
|
+
| `this_week` | `本周`, `这周` | Current week |
|
|
279
|
+
| `next_week` | `下周`, `下一周` | Next week |
|
|
280
|
+
| `next_month` | `下个月`, `下月` | Full next month |
|
|
281
|
+
| `weeks=N` | `N周`, `未来N周` | Next N weeks |
|
|
282
|
+
| `months=N` | `N个月`, `未来N个月` | Next N months |
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## 💻 CLI
|
|
287
|
+
|
|
288
|
+
All core features are accessible via the `fcalendar` command-line tool.
|
|
289
|
+
|
|
290
|
+
### Install
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
pip install fcalendar
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Commands
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
# Time expression recognition → single-line JSON output
|
|
300
|
+
fcalendar query "Spring Festival travel plan"
|
|
301
|
+
# {"input": "Spring Festival travel plan", "result": "Spring Festival travel plan (Today is ..., Spring Festival is ...)"}
|
|
302
|
+
|
|
303
|
+
fcalendar query "下周一开会" --today 2026-03-31
|
|
304
|
+
fcalendar query "meeting next Monday" --lang en
|
|
305
|
+
|
|
306
|
+
# Holiday query → JSON array output
|
|
307
|
+
fcalendar holiday # default: next 180 days
|
|
308
|
+
fcalendar holiday --scope this_week
|
|
309
|
+
fcalendar holiday --scope 本周 # Chinese scope
|
|
310
|
+
fcalendar holiday --scope weeks=3
|
|
311
|
+
fcalendar holiday --scope 未来两个月
|
|
312
|
+
fcalendar holiday --scope next_month --today 2026-09-01
|
|
313
|
+
|
|
314
|
+
# Help
|
|
315
|
+
fcalendar --help
|
|
316
|
+
fcalendar query --help
|
|
317
|
+
fcalendar holiday --help
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## 🛠️ Development
|
|
323
|
+
|
|
324
|
+
This project uses `uv` for dependency management:
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
# Install dependencies
|
|
328
|
+
uv sync
|
|
329
|
+
|
|
330
|
+
# Run all tests
|
|
331
|
+
uv run pytest tests/ -v
|
|
332
|
+
|
|
333
|
+
# Run benchmark tests
|
|
334
|
+
uv run pytest tests/test_benchmark.py::test_benchmark_cases -v -s
|
|
335
|
+
|
|
336
|
+
# Run a single test
|
|
337
|
+
uv run pytest tests/test_benchmark.py::test_basic_query -v
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Test Coverage
|
|
341
|
+
|
|
342
|
+
The project contains **44+ test cases** covering all time expression types:
|
|
343
|
+
|
|
344
|
+
- ✅ Relative time (tomorrow, next week, next month)
|
|
345
|
+
- ✅ Real-time keywords (current time, now, etc.)
|
|
346
|
+
- ✅ Chinese legal holidays
|
|
347
|
+
- ✅ Lunar calendar dates and traditional festivals
|
|
348
|
+
- ✅ Western festivals
|
|
349
|
+
- ✅ 24 solar terms
|
|
350
|
+
- ✅ Seasons and quarters
|
|
351
|
+
- ✅ Specific dates
|
|
352
|
+
- ✅ Year prefixes (last year, next year, 2024, etc.)
|
|
353
|
+
- ✅ Complex combined expressions
|
|
354
|
+
- ✅ Holiday query (public holidays + weekends)
|
|
355
|
+
- ✅ Chinese scope expressions (本周, 未来三周, etc.)
|
|
356
|
+
|
|
357
|
+
Run tests to see detailed results:
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
$ uv run pytest tests/test_benchmark.py::test_benchmark_cases -v -s
|
|
361
|
+
|
|
362
|
+
============================================================
|
|
363
|
+
开始运行 Benchmark 测试,共 47 个用例
|
|
364
|
+
============================================================
|
|
365
|
+
|
|
366
|
+
✅ [relative_weekday_01] PASSED
|
|
367
|
+
✅ [relative_weekend_01] PASSED
|
|
368
|
+
✅ [holiday_spring_festival_01] PASSED
|
|
369
|
+
✅ [current_time_01] PASSED
|
|
370
|
+
...
|
|
371
|
+
============================================================
|
|
372
|
+
测试完成!
|
|
373
|
+
============================================================
|
|
374
|
+
总计: 47 个用例
|
|
375
|
+
成功: 47 个 (100.0%)
|
|
376
|
+
失败: 0 个 (0.0%)
|
|
377
|
+
============================================================
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## 📋 Dependencies
|
|
381
|
+
|
|
382
|
+
- Python >= 3.10
|
|
383
|
+
- chinesecalendar >= 1.9.0 (Chinese legal holiday data)
|
|
384
|
+
- lunardate >= 0.2.2 (Lunar calendar date conversion)
|
|
385
|
+
|
|
386
|
+
## 📂 Project Structure
|
|
387
|
+
|
|
388
|
+
```
|
|
389
|
+
fcalendar/
|
|
390
|
+
├── fcalendar/ # Core package
|
|
391
|
+
│ ├── __init__.py # Package initialization, exports query / holiday
|
|
392
|
+
│ ├── core.py # Core time annotation and holiday query logic
|
|
393
|
+
│ └── cli.py # CLI entry point (fcalendar command)
|
|
394
|
+
├── fcalendar-skill/ # AI Agent skill documentation
|
|
395
|
+
│ └── SKILL.md # Skill config for AI Agent integration
|
|
396
|
+
├── tests/ # Test suite
|
|
397
|
+
│ ├── __init__.py
|
|
398
|
+
│ ├── benchmark.json # Test case data (200+ cases)
|
|
399
|
+
│ └── test_benchmark.py # Test code (44+ test functions)
|
|
400
|
+
├── setup.py # Traditional packaging configuration
|
|
401
|
+
├── pyproject.toml # Modern packaging configuration (uv)
|
|
402
|
+
├── publish.sh # Publishing script (Aliyun PyPI)
|
|
403
|
+
└── README.md # Project documentation
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
## 🔧 Core Functions
|
|
407
|
+
|
|
408
|
+
### `annotate_time_expressions(text, today=None, lang=None)`
|
|
409
|
+
|
|
410
|
+
Main function that recognizes and annotates time expressions in text.
|
|
411
|
+
|
|
412
|
+
**Parameters:**
|
|
413
|
+
- `text` (str): Text to be annotated
|
|
414
|
+
- `today` (datetime.date, optional): Reference date, defaults to current date
|
|
415
|
+
- `lang` (str, optional): Language code ('zh' for Chinese, 'en' for English). If None, automatically detects language
|
|
416
|
+
|
|
417
|
+
**Returns:**
|
|
418
|
+
- str: Annotated text in format `original text (context information)`
|
|
419
|
+
|
|
420
|
+
**Features:**
|
|
421
|
+
- **Multi-language support**: Automatically detects input language and returns output in the same language
|
|
422
|
+
- Automatically deduplicates overlapping annotations, keeping longer (more specific) expressions
|
|
423
|
+
- Supports simultaneous annotation of multiple time expressions
|
|
424
|
+
- Preserves original text integrity, adding annotation information in parentheses
|
|
425
|
+
- Supports real-time queries (returns Beijing time when `today` parameter is not provided)
|
|
426
|
+
|
|
427
|
+
### `query(text, today=None, lang=None)`
|
|
428
|
+
|
|
429
|
+
Convenience function, alias for `annotate_time_expressions`.
|
|
430
|
+
|
|
431
|
+
**Parameters:**
|
|
432
|
+
- `text` (str): Text to be annotated
|
|
433
|
+
- `today` (datetime.date, optional): Reference date, defaults to current date
|
|
434
|
+
- `lang` (str, optional): Language code ('zh' for Chinese, 'en' for English). If None, automatically detects language
|
|
435
|
+
|
|
436
|
+
## 🚀 Publishing
|
|
437
|
+
|
|
438
|
+
Use the provided publishing script:
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
bash publish.sh
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
## 📌 Version Management
|
|
445
|
+
|
|
446
|
+
Current version: **0.11.0**
|
|
447
|
+
|
|
448
|
+
Version numbers need to be synchronized in the following locations:
|
|
449
|
+
- `__version__` in `fcalendar/__init__.py`
|
|
450
|
+
- `version` in `pyproject.toml`
|
|
451
|
+
- `setup.py` automatically reads version from `__init__.py`
|
|
452
|
+
|
|
453
|
+
## 🙏 Acknowledgements
|
|
454
|
+
|
|
455
|
+
This project is built upon the following open-source libraries:
|
|
456
|
+
|
|
457
|
+
- [**chinese-calendar**](https://github.com/LKI/chinese-calendar) — Chinese legal holiday data for Python, by [@LKI](https://github.com/LKI). Used for accurate Chinese public holiday and workday-on-weekend detection.
|
|
458
|
+
- [**python-lunardate**](https://github.com/lidaobing/python-lunardate) — Lunar calendar date conversion for Python, by [@lidaobing](https://github.com/lidaobing). Used for converting between lunar and Gregorian dates, powering traditional festival and lunar date recognition.
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## 📄 License
|
|
463
|
+
|
|
464
|
+
MIT License
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
## 🤝 Contributing
|
|
469
|
+
|
|
470
|
+
Issues and Pull Requests are welcome!
|
|
471
|
+
|
|
472
|
+
## 📝 Changelog
|
|
473
|
+
|
|
474
|
+
### v0.12.0
|
|
475
|
+
- ✨ Added `holiday()` API: query Chinese public holidays and weekends within a specified range
|
|
476
|
+
- ✨ Added CLI (`fcalendar query` / `fcalendar holiday`): all core features accessible via command line
|
|
477
|
+
- ✨ `holiday()` scope supports Chinese and English, including Chinese numerals (一、两、三...十二)
|
|
478
|
+
- ✨ Added `fcalendar-skill/SKILL.md` for AI Agent integration
|
|
479
|
+
- 📝 Updated documentation and test coverage (44+ test functions)
|
|
480
|
+
|
|
481
|
+
### v0.11.0
|
|
482
|
+
- ✨ Added real-time keyword support (current time, now, etc.)
|
|
483
|
+
- ✨ Support for multiple stacking expressions (week after next, three days from now, etc.)
|
|
484
|
+
- 🐛 Fixed edge cases in lunar date recognition
|
|
485
|
+
- 📝 Improved documentation and test cases
|
|
486
|
+
- 🎨 Optimized annotation format for better readability
|