Add your description here
Project description
English | 简体中文
fcalendar
A powerful Python library and CLI tool for recognizing and annotating Chinese/English time expressions, and querying Chinese public holiday schedules.
✨ Features
- 🌍 Multi-language Support: Automatic language detection, supports both Chinese and English input/output
- 🎯 Relative Time: tomorrow, next week, next month, etc.
- 📅 Chinese Legal Holidays: Spring Festival, National Day, Mid-Autumn Festival, etc.
- 🌙 Lunar Calendar: Traditional festivals, lunar dates
- 🎄 Western Festivals: Christmas, Halloween, Valentine's Day, etc.
- 🌸 24 Solar Terms: Spring Equinox, Winter Solstice, etc.
- 🍂 Seasons: Spring, Summer, Autumn, Winter
- 📊 Quarters and Cycles: Q1-Q4, first/second half of year
- 📆 Specific Dates: Supports various date formats
- 🔄 Year Prefixes: last year, next year, 2024, etc.
- ⏰ Real-time: Supports current time queries (returns Beijing time)
- 🗓️ Holiday Query: Query Chinese public holidays and weekends within a specified range
- 💻 CLI Support: All core features accessible via command-line interface
📦 Installation
Install from PyPI
pip install fcalendar
Install from Aliyun PyPI (Internal Network)
pip install fcalendar
Install from Source
git clone https://github.com/youngfreefjs/fcalendar.git
cd fcalendar
pip install -e .
🚀 Quick Start
Python API
from fcalendar import query, holiday
import datetime
# Time expression recognition
result = query("meeting tomorrow", datetime.date(2026, 2, 13))
print(result)
# Output: meeting tomorrow (Today is February 13, 2026, tomorrow is February 14, 2026)
# Holiday query
result = holiday("next_month", datetime.date(2026, 3, 31))
print(result)
# Output: [{'type': 'holiday', 'name': '清明节', 'start': '2026-04-04', 'end': '2026-04-06', 'days': 3}, ...]
CLI
# Time expression recognition
fcalendar query "meeting next Monday"
# Output: {"input": "meeting next Monday", "result": "meeting next Monday (Today is ..., next Monday is April 6, 2026)"}
# Holiday query (supports Chinese and English scope)
fcalendar holiday --scope next_month
fcalendar holiday --scope 本周
fcalendar holiday --scope "weeks=3"
fcalendar holiday --scope 未来两个月
🌍 Language Support
fcalendar supports both Chinese and English with automatic language detection:
Automatic Language Detection
The library automatically detects the input language and returns output in the same language:
# Chinese input → Chinese output
query("明天开会", datetime.date(2026, 2, 13))
# Output: 明天开会(今天是2026 年 2 月 13 日,明天是2026 年 2 月 14 日)
# English input → English output
query("meeting tomorrow", datetime.date(2026, 2, 13))
# Output: meeting tomorrow (Today is February 13, 2026, tomorrow is February 14, 2026)
Manual Language Specification
You can also manually specify the language using the lang parameter:
# Force English output
query("tomorrow", datetime.date(2026, 2, 13), lang='en')
# Output: tomorrow (Today is February 13, 2026, tomorrow is February 14, 2026)
# Force Chinese output
query("明天", datetime.date(2026, 2, 13), lang='zh')
# Output: 明天(今天是2026 年 2 月 13 日,明天是2026 年 2 月 14 日)
Supported English Expressions
- Relative time: today, tomorrow, day after tomorrow, next week, next month
- Weekdays: Monday, Tuesday, next Monday, this weekend, next weekend
- Festivals: Christmas, Halloween, Valentine's Day, Easter, Thanksgiving
- Specific dates: January 15, 2026, July 15th, Jan 15
Note: For Chinese documentation and examples, please see README_CN.md
📖 Usage Examples
Real-time Query
# Query current time (returns Beijing time)
result = query("现在是几点")
print(result)
# Output: 现在是几点(今天是2026 年 3 月 24 日,现在是2026 年 3 月 24 日 21:35:42)
# Supports various current time keywords
keywords = ["当前时间", "现在", "当前", "目前", "此时", "此刻", "眼下", "当下", "这会儿", "这时候", "今天"]
📖 Supported Time Expressions
1️⃣ Relative Time and Real-time
# Relative time
query("meeting tomorrow", datetime.date(2026, 2, 13))
# Output: meeting tomorrow (Today is February 13, 2026, tomorrow is February 14, 2026)
query("travel day after tomorrow", datetime.date(2026, 2, 13))
# Output: travel day after tomorrow (Today is February 13, 2026, day after tomorrow is February 15, 2026)
query("appointment next week", datetime.date(2026, 2, 13))
# Output: appointment next week (Today is February 13, 2026, next week is February 20, 2026)
query("meeting next Monday", datetime.date(2026, 2, 13))
# Output: meeting next Monday (Today is February 13, 2026, next Monday is February 16, 2026)
query("travel next weekend", datetime.date(2026, 2, 13))
# Output: travel next weekend (Today is February 13, 2026, next weekend is February 21, 2026 - February 22, 2026)
query("party this weekend", datetime.date(2026, 2, 13))
# Output: party this weekend (Today is February 13, 2026, this weekend is February 14, 2026 - February 15, 2026)
query("visit museum Wednesday", datetime.date(2026, 2, 13))
# Output: visit museum Wednesday (Today is February 13, 2026, Wednesday is February 18, 2026)
query("business trip next month", datetime.date(2026, 2, 13))
# Output: business trip next month (Today is February 13, 2026, next month is March 1, 2026 - March 31, 2026)
# Real-time keywords (returns Beijing time)
query("what time is it now", datetime.date(2026, 2, 13))
# Output: what time is it now (Today is February 13, 2026, now is Beijing time February 13, 2026 00:00:00)
query("current time", datetime.date(2026, 2, 13))
# Output: current time (Today is February 13, 2026, current time is Beijing time February 13, 2026 00:00:00)
2️⃣ Western Festivals
query("buy gifts for Christmas", datetime.date(2026, 2, 13))
# Output: buy gifts for Christmas (Today is February 13, 2026, Christmas is December 25, 2026)
query("Halloween party", datetime.date(2026, 2, 13))
# Output: Halloween party (Today is February 13, 2026, Halloween is October 31, 2026)
query("Valentine's Day flowers", datetime.date(2026, 2, 13))
# Output: Valentine's Day flowers (Today is February 13, 2026, Valentine's Day is February 14, 2026)
query("Easter church service", datetime.date(2026, 2, 13))
# Output: Easter church service (Today is February 13, 2026, Easter is April 5, 2026)
query("Thanksgiving dinner", datetime.date(2026, 2, 13))
# Output: Thanksgiving dinner (Today is February 13, 2026, Thanksgiving is November 26, 2026)
query("Independence Day fireworks", datetime.date(2026, 2, 13))
# Output: Independence Day fireworks (Today is February 13, 2026, Independence Day is July 4, 2026)
3️⃣ Specific Dates
# Month and day
query("meeting on January 15", datetime.date(2026, 2, 13))
# Output: meeting on January 15 (Today is February 13, 2026, January 15 is January 15, 2027)
query("vacation July 15th", datetime.date(2026, 2, 13))
# Output: vacation July 15th (Today is February 13, 2026, July 15th is July 15, 2026)
# With year
query("conference on January 15, 2027", datetime.date(2026, 2, 13))
# Output: conference on January 15, 2027 (Today is February 13, 2026, January 15, 2027 is January 15, 2027)
4️⃣ Quarters and Cycles
query("Q1 meeting", datetime.date(2026, 2, 13))
# Output: Q1 meeting (Today is February 13, 2026, Q1 is January 1, 2026 - March 31, 2026)
query("Q4 summary", datetime.date(2026, 2, 13))
# Output: Q4 summary (Today is February 13, 2026, Q4 is October 1, 2026 - December 31, 2026)
5️⃣ Complex Combined Examples
# Multiple time expressions
text = "meeting tomorrow, travel next weekend, Christmas party"
result = query(text, datetime.date(2026, 2, 13))
print(result)
# 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)
# Comprehensive example
text = "meeting tomorrow, hotel reservation on July 15th, travel next weekend, visit museum Wednesday, buy gifts for Christmas, Q4 meeting, Easter church service"
result = query(text, datetime.date(2026, 2, 13))
# All time expressions will be correctly recognized and annotated
🗓️ Holiday Query API
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.
from fcalendar import holiday
import datetime
# Next month's holidays
result = holiday("next_month", datetime.date(2026, 3, 31))
# [{'type': 'holiday', 'name': '清明节', 'start': '2026-04-04', 'end': '2026-04-06', 'days': 3},
# {'type': 'weekend', 'name': '周末', 'start': '2026-04-11', 'end': '2026-04-12', 'days': 2}, ...]
# This week
holiday("this_week")
holiday("本周") # Chinese scope also supported
# Next 3 weeks / 2 months
holiday("weeks=3")
holiday("三周") # Chinese numeral
holiday("months=2")
holiday("未来两个月")
Return fields per record:
| Field | Type | Description |
|---|---|---|
type |
str | "holiday" (public holiday) or "weekend" (normal restful weekend) |
name |
str | Name, e.g. "劳动节", "周末" |
start |
str | Start date, ISO format (YYYY-MM-DD) |
end |
str | End date, ISO format (YYYY-MM-DD) |
days |
int | Number of days |
Supported scope values:
| Scope | Alias | Description |
|---|---|---|
half_year |
半年, 未来半年 |
Next 180 days (default) |
this_week |
本周, 这周 |
Current week |
next_week |
下周, 下一周 |
Next week |
next_month |
下个月, 下月 |
Full next month |
weeks=N |
N周, 未来N周 |
Next N weeks |
months=N |
N个月, 未来N个月 |
Next N months |
💻 CLI
All core features are accessible via the fcalendar command-line tool.
Install
pip install fcalendar
Commands
# Time expression recognition → single-line JSON output
fcalendar query "Spring Festival travel plan"
# {"input": "Spring Festival travel plan", "result": "Spring Festival travel plan (Today is ..., Spring Festival is ...)"}
fcalendar query "下周一开会" --today 2026-03-31
fcalendar query "meeting next Monday" --lang en
# Holiday query → JSON array output
fcalendar holiday # default: next 180 days
fcalendar holiday --scope this_week
fcalendar holiday --scope 本周 # Chinese scope
fcalendar holiday --scope weeks=3
fcalendar holiday --scope 未来两个月
fcalendar holiday --scope next_month --today 2026-09-01
# Help
fcalendar --help
fcalendar query --help
fcalendar holiday --help
🛠️ Development
This project uses uv for dependency management:
# Install dependencies
uv sync
# Run all tests
uv run pytest tests/ -v
# Run benchmark tests
uv run pytest tests/test_benchmark.py::test_benchmark_cases -v -s
# Run a single test
uv run pytest tests/test_benchmark.py::test_basic_query -v
Test Coverage
The project contains 44+ test cases covering all time expression types:
- ✅ Relative time (tomorrow, next week, next month)
- ✅ Real-time keywords (current time, now, etc.)
- ✅ Chinese legal holidays
- ✅ Lunar calendar dates and traditional festivals
- ✅ Western festivals
- ✅ 24 solar terms
- ✅ Seasons and quarters
- ✅ Specific dates
- ✅ Year prefixes (last year, next year, 2024, etc.)
- ✅ Complex combined expressions
- ✅ Holiday query (public holidays + weekends)
- ✅ Chinese scope expressions (本周, 未来三周, etc.)
Run tests to see detailed results:
$ uv run pytest tests/test_benchmark.py::test_benchmark_cases -v -s
============================================================
开始运行 Benchmark 测试,共 47 个用例
============================================================
✅ [relative_weekday_01] PASSED
✅ [relative_weekend_01] PASSED
✅ [holiday_spring_festival_01] PASSED
✅ [current_time_01] PASSED
...
============================================================
测试完成!
============================================================
总计: 47 个用例
成功: 47 个 (100.0%)
失败: 0 个 (0.0%)
============================================================
📋 Dependencies
- Python >= 3.10
- chinesecalendar >= 1.9.0 (Chinese legal holiday data)
- lunardate >= 0.2.2 (Lunar calendar date conversion)
📂 Project Structure
fcalendar/
├── fcalendar/ # Core package
│ ├── __init__.py # Package initialization, exports query / holiday
│ ├── core.py # Core time annotation and holiday query logic
│ └── cli.py # CLI entry point (fcalendar command)
├── fcalendar-skill/ # AI Agent skill documentation
│ └── SKILL.md # Skill config for AI Agent integration
├── tests/ # Test suite
│ ├── __init__.py
│ ├── benchmark.json # Test case data (200+ cases)
│ └── test_benchmark.py # Test code (44+ test functions)
├── setup.py # Traditional packaging configuration
├── pyproject.toml # Modern packaging configuration (uv)
├── publish.sh # Publishing script (Aliyun PyPI)
└── README.md # Project documentation
🔧 Core Functions
annotate_time_expressions(text, today=None, lang=None)
Main function that recognizes and annotates time expressions in text.
Parameters:
text(str): Text to be annotatedtoday(datetime.date, optional): Reference date, defaults to current datelang(str, optional): Language code ('zh' for Chinese, 'en' for English). If None, automatically detects language
Returns:
- str: Annotated text in format
original text (context information)
Features:
- Multi-language support: Automatically detects input language and returns output in the same language
- Automatically deduplicates overlapping annotations, keeping longer (more specific) expressions
- Supports simultaneous annotation of multiple time expressions
- Preserves original text integrity, adding annotation information in parentheses
- Supports real-time queries (returns Beijing time when
todayparameter is not provided)
query(text, today=None, lang=None)
Convenience function, alias for annotate_time_expressions.
Parameters:
text(str): Text to be annotatedtoday(datetime.date, optional): Reference date, defaults to current datelang(str, optional): Language code ('zh' for Chinese, 'en' for English). If None, automatically detects language
🚀 Publishing
Use the provided publishing script:
bash publish.sh
📌 Version Management
Current version: 0.11.0
Version numbers need to be synchronized in the following locations:
__version__infcalendar/__init__.pyversioninpyproject.tomlsetup.pyautomatically reads version from__init__.py
🙏 Acknowledgements
This project is built upon the following open-source libraries:
- chinese-calendar — Chinese legal holiday data for Python, by @LKI. Used for accurate Chinese public holiday and workday-on-weekend detection.
- python-lunardate — Lunar calendar date conversion for Python, by @lidaobing. Used for converting between lunar and Gregorian dates, powering traditional festival and lunar date recognition.
📄 License
MIT License
🤝 Contributing
Issues and Pull Requests are welcome!
📝 Changelog
v0.12.0
- ✨ Added
holiday()API: query Chinese public holidays and weekends within a specified range - ✨ Added CLI (
fcalendar query/fcalendar holiday): all core features accessible via command line - ✨
holiday()scope supports Chinese and English, including Chinese numerals (一、两、三...十二) - ✨ Added
fcalendar-skill/SKILL.mdfor AI Agent integration - 📝 Updated documentation and test coverage (44+ test functions)
v0.11.0
- ✨ Added real-time keyword support (current time, now, etc.)
- ✨ Support for multiple stacking expressions (week after next, three days from now, etc.)
- 🐛 Fixed edge cases in lunar date recognition
- 📝 Improved documentation and test cases
- 🎨 Optimized annotation format for better readability
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fcalendar-0.12.0.tar.gz.
File metadata
- Download URL: fcalendar-0.12.0.tar.gz
- Upload date:
- Size: 54.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d2d1e8920bd500c7599df6f8028a7342a11fd3bc6f7d9c4b1ca9f39a32d59d7a
|
|
| MD5 |
19d56ae42549cfd28d9cbc8c999d3522
|
|
| BLAKE2b-256 |
64c0ca666ea4f4e4bf7cd9b9e4046d430e22daf7f0d44ee8e95d72ac0cfa22c3
|
File details
Details for the file fcalendar-0.12.0-py3-none-any.whl.
File metadata
- Download URL: fcalendar-0.12.0-py3-none-any.whl
- Upload date:
- Size: 34.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
26a78860e6eca50335cb615e0d3a275d349351d47608cfe9388b628931c81edd
|
|
| MD5 |
42065eb311713e5463bab542d84ec9f5
|
|
| BLAKE2b-256 |
8524130d6ab54495185bd2ff962abf74a0e1bd36d65d224096cd99d54eb74638
|