Skip to main content

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 annotated
  • today (datetime.date, optional): Reference date, defaults to current date
  • lang (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 today parameter is not provided)

query(text, today=None, lang=None)

Convenience function, alias for annotate_time_expressions.

Parameters:

  • text (str): Text to be annotated
  • today (datetime.date, optional): Reference date, defaults to current date
  • lang (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__ in fcalendar/__init__.py
  • version in pyproject.toml
  • setup.py automatically 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.md for 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fcalendar-0.12.0.tar.gz (54.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fcalendar-0.12.0-py3-none-any.whl (34.5 kB view details)

Uploaded Python 3

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

Hashes for fcalendar-0.12.0.tar.gz
Algorithm Hash digest
SHA256 d2d1e8920bd500c7599df6f8028a7342a11fd3bc6f7d9c4b1ca9f39a32d59d7a
MD5 19d56ae42549cfd28d9cbc8c999d3522
BLAKE2b-256 64c0ca666ea4f4e4bf7cd9b9e4046d430e22daf7f0d44ee8e95d72ac0cfa22c3

See more details on using hashes here.

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

Hashes for fcalendar-0.12.0-py3-none-any.whl
Algorithm Hash digest
SHA256 26a78860e6eca50335cb615e0d3a275d349351d47608cfe9388b628931c81edd
MD5 42065eb311713e5463bab542d84ec9f5
BLAKE2b-256 8524130d6ab54495185bd2ff962abf74a0e1bd36d65d224096cd99d54eb74638

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page