Skip to content

Releases: MelakuDemeke/kenat

v3.2.0

18 Sep 13:58

Choose a tag to compare

Kenat v3.2.0 β€” Distance API and Holiday Helpers

Highlights

  • Human-friendly Ethiopian date distance calculations
  • Low-level diff utilities for advanced use cases
  • Convenience helpers to compute distances to holidays

What’s New

  • Distance API on Kenat instances: distanceTo(target, { units, output })
    • Units: years, months, days (any combination)
    • Output: string (human-friendly) or object (structured)
  • Low-level utility export: diffBreakdown(ethiopianDateA, ethiopianDateB)
  • Holiday helpers:
    • Kenat.distanceToHoliday(holidayName, { direction, units, output })
    • HolidayNames enum for discoverable holiday keys

Why it matters

Answer questions like β€œHow long until Meskel?” or β€œHow many days since 2016/1/1?” with concise, accurate, and Ethiopian-calendar–aware distance results. APIs are composable and suitable for both UI strings and logical calculations.

Install

npm install kenat@^3.2.0

Usage Examples

import Kenat, { diffBreakdown, HolidayNames } from 'kenat';

// Today in Ethiopian calendar
const today = new Kenat();
console.log('Today (ET):', today.format({ lang: 'english' }));

// 1) Difference to a specific Ethiopian date β€” only days
console.log('Days since 2016/1/1:', today.distanceTo('2016/1/1', { units: ['days'], output: 'string' }));

// 2) Difference to a future date β€” months and days
const futureDate = { year: today.getEthiopian().year, month: 13, day: 5 };
console.log('Until 13/5 (this year):', today.distanceTo(futureDate, { units: ['months', 'days'], output: 'string' }));

// 3) Full breakdown (years, months, days) as object
const other = new Kenat('2015/5/10');
console.log('Breakdown (object):', today.distanceTo(other, { units: ['years', 'months', 'days'], output: 'object' }));

// 4) Using low-level diffBreakdown directly on Ethiopian date objects
console.log('diffBreakdown low-level:', diffBreakdown(today.getEthiopian(), other.getEthiopian()));

// 5) Holidays β€” days until next Ethiopian New Year (Enkutatash)
console.log('Days until next Enkutatash:', Kenat.distanceToHoliday(HolidayNames.enkutatash, { direction: 'future', units: ['days'], output: 'string' }));

// 6) Holidays β€” how long ago was Meskel (months and days)
console.log('Since last Meskel:', Kenat.distanceToHoliday(HolidayNames.meskel, { direction: 'past', units: ['months', 'days'], output: 'string' }));

// 7) Holidays β€” closest Meskel (auto chooses nearest past or future) full breakdown
console.log('Nearest Meskel (full):', Kenat.distanceToHoliday(HolidayNames.meskel, { direction: 'auto', units: ['years', 'months', 'days'], output: 'string' }));

Compatibility

  • No breaking changes expected to existing public APIs
  • New exports: diffBreakdown, HolidayNames

Upgrade Notes

  • No code changes required for existing consumers
  • For TypeScript users, ensure your types pick up the new exports if you rely on re-export patterns

Testing

npm test --silent | cat

Method Chaining

15 Sep 16:05

Choose a tag to compare

Changelog

All notable changes to this project will be documented in this file.

3.1.0 - 2025-09-15

Added

  • Method chaining and immutability support in Kenat:
    • add(amount, 'days'|'months'|'years')
    • subtract(amount, 'days'|'months'|'years')
    • startOf('day'|'month'|'year')
    • endOf('day'|'month'|'year')
    • setTime(hour, minute, 'day'|'night') now returns a new instance
  • New test suite tests/methodChaining.test.js covering chaining, immutability, time preservation, error cases, leap-year handling, and boundaries.
  • Type definitions updated in types/Kenat.d.ts to include new chainable APIs.

Changed

  • Existing arithmetic methods now delegate to the new chainable API while preserving backward compatibility:
    • addDays(days), addMonths(months), addYears(years)
    • startOfMonth(), endOfMonth()

Fixed

  • addDays in src/dayArithmetic.js now correctly handles negative day offsets (moving backward across months/years).

Docs

  • Inline JSDoc improvements around new methods (chainability and immutability).

Performance/Behavioral Notes

  • All date operations are immutableβ€”no mutation of the original Kenat instance.
  • Time component is preserved across date arithmetic by default.

Migration Notes

  • No breaking changes. Existing APIs continue to work.
  • Prefer new chainable methods for more fluent and readable code.

Examples

  • Basic chaining
const date1 = new Kenat('2017/1/1');
const future = date1.add(7, 'days').add(1, 'months').add(1, 'years');
console.log('Original:', date1.format());
console.log('After chaining:', future.format());
console.log('Result:', future.getEthiopian());

Output:

Original: መሡከረም 1 2017
After chaining: αŒ₯α‰…αˆα‰΅ 8 2018
Result: { year: 2018, month: 2, day: 8 }
  • Subtract operations
const date2 = new Kenat('2017/1/1');
const past = date2.subtract(7, 'days').subtract(1, 'months').subtract(1, 'years');
console.log('Original:', date2.format());
console.log('After subtracting:', past.format());
console.log('Result:', past.getEthiopian());

Output:

Original: መሡከረም 1 2017
After subtracting: αˆ€αˆαˆŒ 29 2015
Result: { year: 2015, month: 11, day: 29 }
  • Mixed add and subtract
const date3 = new Kenat('2017/1/1');
const mixed = date3.add(7, 'days').subtract(1, 'months').add(1, 'years');
console.log('Original:', date3.format());
console.log('After mixed operations:', mixed.format());
console.log('Result:', mixed.getEthiopian());

Output:

Original: መሡከረም 1 2017
After mixed operations: αŒ³αŒ‰αˆœ 5 2017
Result: { year: 2017, month: 13, day: 5 }
  • Time preservation
const date4 = new Kenat('2017/1/1', { hour: 3, minute: 30, period: 'day' });
const withTime = date4.add(7, 'days').add(1, 'months');
console.log('Original:', date4.toString());
console.log('After operations:', withTime.toString());
console.log('Time preserved:', withTime.time);

Output:

Original: መሡከረም 1 2017 03:30 αŒ α‹‹α‰΅
After operations: αŒ₯α‰…αˆα‰΅ 8 2017 03:30 αŒ α‹‹α‰΅
Time preserved: { hour: 3, minute: 30, period: 'day' }
  • startOf and endOf chaining
const date5 = new Kenat('2017/6/15');
const res = date5.startOf('month').add(7, 'days').endOf('day');
console.log('Original:', date5.format());
console.log('After startOf/endOf:', res.format());
console.log('Time set to:', res.time);

Output:

Original: α‹¨αŠ«α‰²α‰΅ 15 2017
After startOf/endOf: α‹¨αŠ«α‰²α‰΅ 8 2017
Time set to: { hour: 12, minute: 0, period: 'night' }
  • Complex chaining
const date6 = new Kenat('2017/1/1');
const complex = date6
  .startOf('month')
  .add(14, 'days')
  .setTime(12, 0, 'day')
  .add(1, 'months')
  .endOf('day')
  .add(1, 'years');
console.log('Original:', date6.format());
console.log('After complex chaining:', complex.format());
console.log('Final result:', complex.getEthiopian());

Output:

Original: መሡከረም 1 2017
After complex chaining: αŒ₯α‰…αˆα‰΅ 15 2018
Final result: { year: 2018, month: 2, day: 15 }
  • Leap year handling
const leapDate = new Kenat('2015/13/6');
const leapResult = leapDate.add(1, 'days').add(1, 'months');
console.log('Original (leap year):', leapDate.format());
console.log('After operations:', leapResult.format());
console.log('Result:', leapResult.getEthiopian());

Output:

Original (leap year): αŒ³αŒ‰αˆœ 6 2015
After operations: αŒ₯α‰…αˆα‰΅ 1 2016
Result: { year: 2016, month: 2, day: 1 }

Calendar Modes & Data Structure Overhaul

20 Jun 15:37

Choose a tag to compare

This release marks a significant step forward for the Kenat library, introducing powerful new ways to view and filter the calendar. The highlight is the new Calendar Modes feature, alongside major improvements to the data structures and overall code quality that make the library more robust and easier to maintain.

✨ New Features

  • Calendar Modes: You can now initialize the calendar in one of several modes to exclusively display certain types of holidays:

    • Public Holidays Mode: A mode to display only official non-working public holidays. This is now the default mode for the Kenat.getMonthCalendar() static method.
    • Christian Mode: A comprehensive mode for Christian holidays, showing movable feasts from Bahire Hasab (like Fasika), major fixed holidays, and recurring monthly saints' days.
    • Muslim Mode: A dedicated mode for Muslim holidays, which also automatically highlights every Friday as "Jummah" on the calendar grid.
  • Saints' Day Filter: Within Christian Mode, a new option allows users to toggle between viewing only major annual feasts ("Nigs") or showing all daily saints' commemorations for a less cluttered view.

πŸ› οΈ Improvements & Refactoring

  • Refactored nigs.js Data Structure: The data structure for saints with multiple annual commemorations (e.g., Abuna Takla Haymanot) has been refactored. Events are now nested under a single parent saint object, eliminating data redundancy and making the structure more logical and scalable.
  • Refactored MonthGrid Logic: The core generate() method in the MonthGrid class has been broken down into smaller, single-responsibility helper methods. This significantly improves code readability and makes future maintenance and feature development easier.
  • Updated Holiday Data: Siklet (Good Friday) is now correctly tagged as a PUBLIC holiday, ensuring it appears in the "Public Holidays" mode.

βœ… Fixes

  • Fixed an issue where the calendar UI could fail to display certain holidays when multiple event types (e.g., a public holiday and a saint's day) occurred on the same date. The new styling logic correctly handles overlapping events.
  • Resolved bugs in the demo application where navigation buttons and event modals would become unresponsive after certain operations.

v2.0.0

12 Jun 19:46

Choose a tag to compare

Description:

a major enhancement to the library by adding a complete, authentic Bahire Hasab (α‰£αˆ•αˆ¨ αˆƒαˆ³α‰₯) calculation engine and a powerful new API for querying and filtering holidays. This makes kenat a more comprehensive and robust tool for developers building applications that require deep Ethiopian calendar and liturgical context.


✨ Key Changes

1. Bahire Hasab Calculation Engine (/src/bahireHasab.js)

  • A new, self-contained module has been created to handle all traditional calculations based on the Bahire Hasab system.
  • It accurately computes foundational values like Amete Alem, Wenber, Metqi, and the date of Nineveh.
  • This module is now the single source of truth for all movable feast calculations, ensuring authenticity and maintainability.

2. Advanced Holiday API

  • getHoliday(holidayKey, year, options): A new top-level function to fetch a single, fully-detailed holiday object for a given year.
  • getHolidaysForYear(year, options): A new convenience function to get a complete, sorted list of all holidays (fixed and movable) for an entire year.
  • .isHoliday() Method: A new method on the Kenat class instance to easily check if any specific date is a holiday. new Kenat('2017/1/17').isHoliday()
  • .getBahireHasab() Method: A new method on the Kenat class that returns a rich object containing all calculated Bahire Hasab values and the dates of all movable feasts for that year.

3. Powerful Holiday Filtering

  • The getHolidaysInMonth, getHolidaysForYear, and MonthGrid functions now accept a filter option.
  • Developers can easily request only the holidays they need by providing a single tag (e.g., { filter: 'public' }) or an array of tags ({ filter: ['christian', 'muslim'] }).
  • The HolidayTags object is now exported, allowing for safe and readable filtering.

4. Internationalization (i18n) & Data Refactoring

  • Full i18n for Holidays: All holiday names and descriptions have been moved to a centralized holidayInfo constant, allowing for easy translation and maintenance.
  • Bahire Hasab i18n: The .getBahireHasab() method now accepts a lang option and returns translated names for the Evangelist and New Year's Day.
  • DRY Principle: The core calculation logic in bahireHasab.js has been refactored into a single internal "engine" to avoid code duplication and improve maintainability.

5. Bug Fixes

  • The logic for calculating Islamic holidays has been completely rewritten to correctly handle cases where holidays (like Moulid) can occur twice in the same Ethiopian solar year.
  • Fixed a circular dependency between the Kenat and bahireHasab modules.

This update significantly enhances the library's capabilities, making it a more powerful, convenient, and authentic resource for Ethiopian calendar development.

v1.5.1

10 Jun 19:58

Choose a tag to compare

Full Changelog: v1.5.0...v1.5.1

v1.4.0

07 Jun 09:12

Choose a tag to compare

πŸš€ Kenat v1.4.0 Released! πŸ‡ͺπŸ‡ΉπŸ•’
Enhanced Ethiopian Time Support

We’re excited to announce Kenat v1.4.0 β€” a major update focused on Ethiopian time calculations and formatting. This release brings powerful and flexible tools to work with Ethiopian time, including conversions, math, and display.

πŸ”§ What’s New in v1.4.0

βœ… New module: Time.js
– Introduces a clean, object-oriented Time class
– Supports:
β€’ add() / subtract() Ethiopian time durations
β€’ diff() for time difference
β€’ format() with Geez numerals, custom styles

βœ… Renamed:
– timeConverter.js β†’ ethiopianTime.js (more intuitive)

βœ… Functional Utilities Added to ethiopianTime.js:
– addEthiopianTime()
– subtractEthiopianTime()
– getTimeDifference()
– formatEthiopianTime()

βœ… Improved Formatting:
– Display times with options like Geez numerals, period labels (α‰€αŠ•/αˆŒαˆŠα‰΅), and minimal style


πŸ“¦ Update Now

npm install [email protected]

πŸ“š Docs & examples coming soon.

v1.3.1

05 Jun 19:31

Choose a tag to compare

What's Changed

  • Add flexible date formatting with language, weekday, Geez numerals, and time options to Ethiopian calendar by @MelakuDemeke in #12
  • Add holiday names and enhance Islamic date conversions by @MelakuDemeke in #13

Full Changelog: v1.3.0...v1.3.1

v1.0.0

04 Jun 10:41

Choose a tag to compare

What's Changed

  • Add time support to Kenat constructor and string output by @MelakuDemeke in #5

Full Changelog: v0.1.1...v1.0.0