Skip to main content

CQCalendar v1.5.0

CQCalendar is a customizable, tick-based time and calendar system for Python games and simulations.

It is designed for RPGs, sandbox sims, and systemic games, where time drives world behavior rather than just displaying a UI clock.

CQCalendar supports custom calendars, custom lunar cycles, and advanced moon phase configuration, making it suitable for fantasy, sci-fi, and procedural worlds.


Features

  • Tick-based and absolute time progression
  • Fully custom calendar support
  • Custom month names & day counts
  • Custom weekday names
  • Optional Gregorian leap year logic
  • Custom synodic lunar cycle (length of moon cycle)
  • Custom moon phases (names, ranges, & colors)
  • Moon illumination calculation
  • Configurable day/night windows (hour + minute precision)
  • Full calendar preset JSON import/export
  • Lunar phase-only JSON import/export
  • Day/Night helper functions (is_night / is_day)
  • Event callbacks for hour/day/month/year changes
  • Designed for decoupled, systemic game logic
  • No external dependencies

Installation

You can install CQCalendar using pip.

pip install cqcalendar

How to Create a Calendar for Your Game

import cqcalendar

calendar = cqcalendar.CQCalendar(
	hour=9,
	minute=0,
	is_pm=False,
	minutes_per_tick=1,
	day=1,
	month=1,
	year=1,
	weekday=0,
	months=[
		{"name": "Frostwane", "days": 31},
		{"name": "Emberfall", "days": 28},
		{"name": "Stonewake", "days": 31},
	],
	weekdays=["Firstday", "Secondday", "Thirdday", "Fourthday"],
	synodic_month_days=20.0,
	use_gregorian_leap_years=False,
)

Time

How to Display Current Time

print(calendar.time_string())

How to Change Time

calendar.set_time(hour=12, minute=0, is_pm=True)

How to Increment Time

calendar.update(ticks=10)

Date

How to Display Current Date

print(calendar.date_string())

How to Change Date

calendar.set_date(day=31, month=12, year=1)

Absolute Time Advancement

You can advance time directly without ticks.

calendar.add_minutes(30)
calendar.add_hours(6)
calendar.add_days(1)
calendar.add_months(1)
calendar.add_years(1)

Or you can do it in a single method.

calendar.add(days=3, hours=4)

Weekdays

Weekdays are zero-indexed (0 = Monday, 6 = Sunday).

How to Display Weekday

print(calendar.weekday_name())

How to Change Weekday

calendar.set_weekday(weekday=1)

Lunar Cycle

CQCalendar includes a synodic lunar cycle (approximately 29.53 days)

How to Display Moon Phase

print(calendar.moon_phase_name())

How to Set Moon Phase

calendar.set_moon_phase("Waning Crescent")

The above is an alternative to using moon_age_days:

# Precise numeric control still supported
calendar = CQCalendar(moon_age_days=14.77) # Full Moon

If both moon_phase and moon_age_days are provided, moon_phase takes priority.

How to Get Moon Illumination

print(calendar.moon_illumination())

Useful for:

  • werewolf systems
  • rituals
  • night visibility
  • tides or magic strength

Custom Moon Phases

moon_phases = [
	{"name": "New Moon", "start": 0.00, "end": 0.10, "color_hex": "#000000"},
	{"name": "Waxing Crescent", "start": 0.10, "end": 0.25, "color_hex": "#aaaaaa"},
	{"name": "Blood Moon", "start": 0.45, "end": 0.55, "color_hex": "#ff0000"},
]

calendar = cqcalendar.CQCalendar(
	moon_phases=moon_phases,
	synodic_month_days=20.0,
)

Get Moon Color

print(calendar.moon_color_hex())
print(calendar.moon_color_rgb())

Lunar Phase JSON Import / Export

CQCalendar supports importing and exporting lunar phase definitions via JSON.

calendar.export_lunar_phases_json("lunar_phases.json")
calendar.import_lunar_phases_json("lunar_phases.json")

This allows CQCalendar to interoperate cleanly with tools such as MoonTex and future editors.


Day / Night Helpers

CQCalendar includes helper functions to determine whether the current time is within a night window.

This is useful for day/night cycles and showing moon textures (e.g. when using CQCalendar with MoonTex).

Check If It's Night

Default night window: 7:00 PM → 6:00 AM

print(calendar.is_night())

Use a Custom Night Window

Example: 8:30 PM → 5:45 AM

print(calendar.is_night(
	night_start_hour=8,
	night_start_minute=30,
	night_start_is_pm=True,
	night_end_hour=5,
	night_end_minute=45,
	night_end_is_pm=False,
))

Night window settings can also be defined once on initialization and reused automatically.

Check If It's Day

print(calendar.is_day())

Callbacks (Events)

CQCalendar allows systems to react to time changes using callbacks.

Callbacks are triggered when time crosses a boundary (hour/day/month/year), not continuously.

Hourly Event

def restock_shops(calendar):
  if calendar.hour == 6 and not calendar.is_pm:
    print("Shops restocked!")

calendar.on_hour(restock_shops)

Daily Event

def payday(calendar):
  if calendar.day == 1:
    print("Rent is due!")

calendar.on_day(payday)

Available callbacks:

  • on_hour
  • on_day
  • on_month
  • on_year

Full Calendar Preset

CQCalendar can export all settings - time, date, calendar, and lunar - to one JSON file.

Export Full Preset

calendar.export_settings_json("my_calendar.json")

Import Full Preset

calendar.import_settings_json("my_calendar.json")

Misc.

How to Display Current Date and Time

print(calendar.datetime_string())

Check Leap Year

print(calendar.is_leap_year())

Internal Representation

print(repr(calendar))

Related Tools

  • CQCalendar Studio: Visual calendar editor (coming soon)

Related Libraries

  • TerraForge: A versatile Python toolset for procedural map generation.
  • MoonTex: A noise-based texture generator that creates realistic grayscale moon phase images.

Metadata

Release files for cqcalendar 1.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cqcalendar 1.5.0
File Size Uploaded Provenance Actions
cqcalendar-1.5.0.tar.gz 12.8 kB Without provenance Details for cqcalendar-1.5.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for cqcalendar 1.5.0
File Interpreter ABI Platform Actions
cqcalendar-1.5.0-py3-none-any.whl Python 3 none any Details for cqcalendar-1.5.0-py3-none-any.whl

Total release size: 23.0 kB

Release files / cqcalendar-1.5.0.tar.gz

Download URL cqcalendar-1.5.0.tar.gz
Size 12.8 kB
Tags Source
SHA-256 checksum
How to use checksums
26a32ec8d71ef3727a4b9822b7ae0e9800000890148ae9a62119316d6141ed13
BLAKE2b-256 checksum
How to use checksums
67f5c6a5372a772f75fb2f9dff1ddcdc217c2829494ac48571c41021c8e22a7d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.7

Release files / cqcalendar-1.5.0-py3-none-any.whl

Download URL cqcalendar-1.5.0-py3-none-any.whl
Size 10.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e1997baec72c15cd987a3228d1d07243a6462fdb380fd77b302fd74c6f925d13
BLAKE2b-256 checksum
How to use checksums
ca7792da5383c476b3fcc3770d2db038f1e779a9229c69759ea3c4293dba7acb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.7

Security for cqcalendar 1.5.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page