# cnlunar replaces the Shouxing solar term formula with Hong Kong Observatory tables

> cnlunar is a dependency-free Python library for the Chinese lunisolar calendar that takes its solar term data from the Hong Kong Observatory tables instead of an empirical formula, and adds the daily auspicious and inauspicious content of the Qinding Xiejian Bianfang Shu. It suits Python developers who need Chinese calendar output without a database.

**OPN48/cnlunar** — 农历，中国农历历法项目，无需数据库环境，以《钦定协纪辨方书》为核心的python3 农历、黄历、二十四节气、节假日、星次、每日凶煞、每日值神、农历建除十二神、农历每日宜忌、彭祖百忌、每日五行、二十八星宿、天干地支、农历生辰八字、时辰凶吉等开源项目。

- Repository: https://github.com/OPN48/cnlunar
- Stars: 857 · Forks: 200
- Language: Python
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/opn48-cnlunar

## Why the Shouxing formula was dropped

The project's starting point is a criticism of a formula many Chinese calendar libraries still use. The README describes the so called general Shouxing formula, written as [Y*D+C]-L, as an empirical formula that fits a constant C to approximate the real solar terms, then patches the results with correction values for particular years. The reasoning is that the same coefficient table has to be read differently for 1901 to 2000, for the first four solar terms of 2000, and for 2000 to 2100, and that within two centuries there are 22 years needing their own correction. The stated consequence is a chain reaction: a wrong solar term date corrupts the lunar date, then the month pillar of the bazi expression, then the daily yi and ji output.

## Hong Kong Observatory tables as the fixed reference

The replacement is a data source rather than a cleverer equation. The README describes two options considered. The first was geometric, using a 15 degree solar longitude and the shape of the Earth's elliptical orbit with Kepler's second law, and it says the computed values came very close to the Hong Kong Observatory data but still differed, because the Earth, Moon and Sun are a three body problem that cannot be predicted perfectly, Jupiter's pull is small but not zero, and the Sun itself moves so the tropical year oscillates around the sidereal year. The second option was to use the Purple Mountain Observatory in Hong Kong and its conversion tables covering 1901 to 2100, and the project chose that. The argument is that the calendar is astronomical science and a calendar detached from observation loses that basis.

## One Lunar object, common data eagerly and rare data lazily

The API is deliberately narrow so that a new user has one thing to learn. The core algorithm is packaged as a single class, and all the lunar data conversion goes through one `Lunar` object. The README explains the split: data for the calendar section and the commonly used traditional section is generated when the class is initialised, while less commonly used traditional and supplementary data is computed on demand. So a caller constructs `cnlunar.Lunar` with a datetime, and then reads attributes off that object. The demo passes a `godType` argument of `8char` for the conventional calculation, and the README notes that a Hong Kong style month pillar algorithm is the default while a text based lunar month algorithm is also supported, with the details in `demo.py`.

## Three groups of output: calendar, tradition and western extras

What the object exposes is grouped in the README into three parts. The calendar part covers Gregorian to lunar conversion in numeric form, the 24 solar terms and the season. The traditional part is much larger: bazi character expressions, daily yi and ji, the twelve day officers, the 28 lunar mansions, nayin, the 72 pentads, the double-hour divisions, the east zodiac, Peng Zu taboos, the meridian table for each time period, and lunar festivals. The supplementary part adds constellations, Gregorian holidays and common western holidays. The traditional layer is where the sourcing is unusual. The content comes from the Qinding Xiejian Bianfang Shu, and the README argues that each entry there has a basis, following the graded tables of what is suitable and what to avoid, with both civil and official matters distinguished.

## No database and no third-party libraries

The distribution constraint is what makes it easy to adopt. The design section of the README states the goal as a program that installs easily, includes no SQL or other database, depends only on the Python standard library, works with a plain pip install, and ships a usage example. The data is therefore held inside the package: solar term, Spring Festival and leap month data are stored as hexadecimal and vector-compressed in the code, and `solar24.py` decompresses 200 years of solar term data for the core module to use. `config.py` holds configuration data for lunar dates, solar terms and constellations, `holidays.py` holds Gregorian and lunar holiday data, and `tools.py` holds data type conversion and cleaning helpers. The library also explains why it avoids a database on technical grounds, noting that the algorithm is a calculation rather than a lookup over a growing corpus.

## Installing from PyPI and reading a first date

The package is published on PyPI, so installation is a single command:

```bash
$ pip3 install cnlunar
```

The usage example in the README starts with the standard library and the package itself:

```python
import datetime
import cnlunar
```

and then constructs a `Lunar` object from a datetime. The project metadata pins the distribution name and version:

```toml
[project]
name = "cnlunar"
version = "0.2.5"
```

Everything else in the demo is attribute access on that object, so a typical caller asks for the lunar date, the day of the week, the current and next solar term, the bazi characters, the twelve day officers, the 28 mansions, the Peng Zu taboos, the good and bad gods of the day, and the day's yi and ji list, then prints them with a small loop. The demo also exposes two conveniences: a legal holiday list and two other holiday lists for the day.

## The module layout and the original text kept in comments

The directory design is described in the README and explains where to look when output surprises you. `lunar.py` is the core module, supporting the calendar, traditional and supplementary calculations, and it keeps a large amount of the original text of the Qinding Xiejian Bianfang Shu as comments so that a discrepancy in output can be traced back and corrected. `demo.py` is the usage example that doubles as the quick start template during development. `config.py` and `holidays.py` hold configuration and holiday data, `solar24.py` handles decompression of the solar term table, and `tools.py` handles conversions. The design notes also set out the rules the daily deity and inauspicious day scripts follow, including that an object has a fixed name, that it has a duty time tied to the solar and lunar year, month and day, and that different objects carry different ranks, so the printed yi and ji list needs trimming.

## Ports to other languages and the other no-dependency project

The README links a family of related projects, which tells you what the data model looks like from the outside. There is a JavaScript version, a Dart and Flutter version, a Kotlin version for Android, a C# version for VRChat, a Flask web service wrapper, and an offline Flutter application called rishu. It also names another dependency-free Chinese lunar project, lunar-python by 6tail, as an alternative worth knowing about. The difference in approach is the one this project has already explained: the traditional cultural layer, the graded yi and ji tables drawn from the book, the alternative month pillar calculation, and the Hong Kong Observatory table as the fixed solar term source. If your requirement is only calendar conversion and you have no interest in the yi and ji content, lunar-python is the simpler dependency in the same family. The licence here is MIT, and the release history shows version 0.2.5 published on 2026-10-09 fixing the jiukong calculation, after 0.2.4 on 2026-02-04 and 0.2.2 on 2026-02-02 which fixed an OCR bug involving the characters for ji and si. The repository is not archived and the last push was on 2026-10-09.

## Conclusion

Adopt cnlunar when a Python project needs Chinese lunisolar dates, solar terms or the traditional daily yi and ji tables and you want zero dependencies and no database, since the library uses only the Python standard library and stores its data inside the package. Do not adopt it if you need the full traditional content of the Qinding Xiejian Bianfang Shu in a form the library does not expose, because the traditional layer is expressed through per-day objects rather than a general date selection engine. Verify first that your deployment Python version is supported and that the version you install is 0.2.5 or later, since the most recent release fixed the jiukong calculation.

## FAQ

### How do I install cnlunar and get a Chinese lunar date?

Run `pip3 install cnlunar`, then construct a `Lunar` object with a datetime, for example `cnlunar.Lunar(datetime.datetime(2022, 11, 14, 10, 30), godType='8char')`. All the calendar and traditional data is then read as attributes on that object.

### Does cnlunar need a database or any third-party library?

No. The design aims for a package that depends only on the Python standard library, with no SQL or other database, and the solar term and holiday data stored compressed inside the package itself.

### Where does cnlunar get its solar term dates?

From the Hong Kong Observatory conversion tables covering 1901 to 2100, used as the fixed reference instead of an empirical solar term formula with per-year correction values.

### What traditional calendar content does cnlunar provide?

The README lists daily yi and ji, the twelve day officers, the 28 lunar mansions, nayin, the 72 pentads, the double hours, Peng Zu taboos, the east zodiac, the nine fly stars, the fetal god and the daily auspicious and inauspicious gods, with the content based on the Qinding Xiejian Bianfang Shu.

### Which licence is cnlunar released under?

MIT, with the licence file referenced from the project metadata. The latest listed release is 0.2.5, published on 2026-10-09.

## Sources

- [Issues](https://github.com/OPN48/cnlunar/issues)
- [License: MIT](https://github.com/OPN48/cnlunar/blob/master/LICENSE)
- [OPN48/cnlunar on GitHub](https://github.com/OPN48/cnlunar)
- [README](https://github.com/OPN48/cnlunar/blob/master/README.md)
- [Releases](https://github.com/OPN48/cnlunar/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/opn48-cnlunar
