🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

kenat

Package Overview
Dependencies
Maintainers
1
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

kenat

A JavaScript library for the Ethiopian calendar with date and time support.

latest
Source
npmnpm
Version
4.0.0
Version published
Weekly downloads
467
0.43%
Maintainers
1
Weekly downloads
 
Created
Source

Kenat / ቀናት NPM Version

banner

Build Status npm bundle size GitHub issues GitHub Repo stars GitHub forks GitHub commit activity npm downloads

Kenat / ቀናት

📌 Overview
Kenat (Amharic: ቀናት) is a comprehensive JavaScript library for the Ethiopian calendar. It provides a complete toolset for developers, handling date conversions, advanced formatting, full date arithmetic, and a powerful, authentic holiday calculation system based on the traditional Bahire Hasab (ባሕረ ሃሳብ).

📚 Table of Contents

✨ Features

  • 🔄 Bidirectional Conversion: Seamlessly convert between Ethiopian and Gregorian calendars with high precision.
  • 🌓 Calendar Preference: Read or format any date as Ethiopian or Gregorian with a single { calendar } option — no if/else needed at call sites.
  • 🗂️ Complete Holiday System: Pre-loaded with all public, religious (Christian & Muslim), and cultural holidays.
  • 🔎 Advanced Holiday Filtering: Easily filter holidays by tags (e.g., public, christian, muslim).
  • 📖 Authentic Liturgical Calculations: Implements Bahire Hasab (ባሕረ ሃሳብ) for movable feasts and fasts, including edge-case years.
  • 🔠 Localized Formatting: Display dates in both Amharic and English with multiple format options.
  • 🔢 Geez Numerals: Convert numbers and dates to traditional Geez numeral equivalents.
  • Full Date Arithmetic: Add or subtract days, months, and years with support for the 13-month calendar.
  • ⏱️ Start / End of Period: Snap any date to the start or end of its day, month, or year (leap-year aware).
  • ⚖️ Date Comparison: isBefore, isAfter, isSameDay, isSameMonth, and isSameYear for clean, readable comparisons.
  • ↔️ Date Difference & Distance API: Calculate precise differences and human-friendly distances between dates.
  • 🕒 Ethiopian Time: Convert between 24-hour Gregorian and 12-hour Ethiopian time systems.
  • 🗓️ Calendar Generation: Create monthly or yearly calendar grids with customizable options.
  • 🕌 Fasting Periods: Calculate Orthodox Christian fasting periods and Islamic Ramadan dates.
  • 📅 Date Range Generation: Generate arrays of dates between two Ethiopian dates.
  • 🏷️ Holiday Distance Helpers: Find distances to next/previous holiday occurrences.
  • 📊 Multiple Output Formats: Support for ISO strings, JSON serialization, custom formatting, and structured data.
  • 🧊 Immutable & Chainable: Every method that changes a date returns a new Kenat instance, so chaining is always safe.
  • 📦 Zero Dependencies: Pure JavaScript, no runtime dependencies.

🚀 Installation

npm install kenat

Requirements

Node.js 18 or later. Kenat ships zero runtime dependencies and both module formats — import (ESM) and require() (CJS) both work, so there's no need for a dynamic import() workaround in CommonJS projects. A minified browser build (dist/index.global.js, global Kenat) is also published for plain <script> tag / CDN use via unpkg.

TypeScript Support

Kenat is written in TypeScript and ships its own .d.ts declarations — no additional type packages needed, and the types are guaranteed to match the implementation since they're generated from the same source, not hand-maintained separately.

import Kenat from 'kenat';
import type { EthiopianDate, Holiday } from 'kenat';

const today: Kenat = new Kenat();
const date: EthiopianDate = today.getEthiopian();

Import Options

// Default import (Kenat class)
import Kenat from 'kenat';

// Named imports for utilities
import { 
  getHolidaysForYear, 
  getHolidaysInMonth,
  getHoliday,
  HolidayTags, 
  HolidayNames,
  toGeez, 
  toArabic,
  toEC, 
  toGC,
  diffBreakdown,
  getFastingPeriod,
  getFastingInfo,
  getFastingDays,
  getBahireHasab,
  monthNames,
  MonthGrid,
  Time
} from 'kenat';

🔰 Quick Start

Get today's Ethiopian date:

import Kenat from 'kenat';

const today = new Kenat();

console.log(today.getEthiopian());
// → { year: 2018, month: 1, day: 8 }

console.log(today.format({ lang: 'english', showWeekday: true }));
// → "Thursday, Meskerem 8 2018"

// Get Gregorian equivalent
console.log(today.getGregorian());
// → { year: 2025, month: 9, day: 19 }

// Format with time
const withTime = today.setTime(8, 30, 'day');
console.log(withTime.format({ includeTime: true }));
// → "2018/1/8 8:30 day"

🧭 Design Principles

  • Immutable & chainable — every method that "changes" a date (.add(), .startOf(), .setTime(), ...) returns a new Kenat instance rather than mutating the original. This makes chaining predictable and safe:

    const future = new Kenat()
      .add(2, 'years')
      .add(3, 'months')
      .startOf('month');
    
  • Ethiopian-first, calendar-agnostic where it counts — dates are stored internally as Ethiopian {year, month, day}, but every user-facing accessor and formatter (getDate, format, toString, toISOString) accepts a { calendar: 'ethiopian' | 'gregorian' } option, so building calendar-switchable UIs doesn't require branching logic in your own code.

  • No hidden state — options are always passed explicitly per call (options = {}), matching the rest of the library's style; there's no global or instance-level configuration to keep track of.

⛪ Bahire Hasab & Holiday System

Get All Holidays for a Year

import { getHolidaysForYear } from 'kenat';

const holidaysIn2017 = getHolidaysForYear(2017);

console.log(holidaysIn2017.find(h => h.key === 'fasika'));
// Output for Fasika (Easter) in 2017
{
  key: 'fasika',
  tags: ['public', 'religious', 'christian'],
  movable: true,
  name: 'ፋሲካ',
  description: 'የኢየሱስ ክርስቶስን ከሙታን መነሣት ያከብራል።...',
  ethiopian: { year: 2017, month: 8, day: 12 },
  gregorian: { year: 2025, month: 4, day: 20 }
}

Filter Holidays by Tag

import { getHolidaysForYear, HolidayTags } from 'kenat';

const publicHolidays = getHolidaysForYear(2017, {
  filter: HolidayTags.PUBLIC
});

const religiousHolidays = getHolidaysForYear(2017, {
  filter: [HolidayTags.CHRISTIAN, HolidayTags.MUSLIM]
});

Check if a Specific Date is a Holiday

const meskel = new Kenat('2017/1/17');
console.log(meskel.isHoliday()); // → Returns the Meskel holiday object

const notHoliday = new Kenat('2017/1/18');
console.log(notHoliday.isHoliday()); // → []

Access Bahire Hasab Calculations

const bahireHasab = new Kenat('2017/1/1').getBahireHasab();

console.log(bahireHasab.evangelist);
// → { name: 'ማቴዎስ', remainder: 1 }

console.log(bahireHasab.movableFeasts.fasika.ethiopian);
// → { year: 2017, month: 8, day: 21 }
// Full output of .getBahireHasab() for 2017
{
  ameteAlem: 7517,
  meteneRabiet: 1879,
  evangelist: { name: 'ማቴዎስ', remainder: 1 },
  newYear: { dayName: 'ረቡዕ', tinteQemer: 2 },
  medeb: 12,
  wenber: 11,
  abektie: 1,
  metqi: 29,
  bealeMetqi: { date: { year: 2017, month: 1, day: 29 }, weekday: 'Wednesday' },
  mebajaHamer: 3,
  nineveh: { year: 2017, month: 6, day: 3 },
  movableFeasts: {
    nineveh: { /* ... */ },
    abiyTsome: { /* ... */ },
    fasika: {
      key: 'fasika',
      tags: ['public', 'religious', 'christian'],
      movable: true,
      name: 'ፋሲካ',
      description: 'የኢየሱስ ክርስቶስን ከሙታን መነሣት ያከብራል።...',
      ethiopian: { year: 2017, month: 8, day: 12 },
      gregorian: { year: 2025, month: 4, day: 20 }
    },
    // ... other movable holidays
  }
}

The Bahire Hasab engine correctly handles edge-case years where the traditional Metqi calculation lands on 0/30 (e.g. 2006 E.C.), so movable feast dates stay accurate every year.

➕ More API Examples

Date Arithmetic

const today = new Kenat();
const nextWeek = today.addDays(7);
const lastMonth = today.addMonths(-1);

// Fluent API
const future = today.add(2, 'years').add(3, 'months').add(15, 'days');

Comparing Dates

const a = new Kenat('2016/1/1');
const b = new Kenat('2016/2/5');

a.isBefore(b);    // → true
b.isAfter(a);     // → true
a.isSameDay(a);   // → true
a.isSameMonth(b); // → false (different months)
a.isSameYear(b);  // → true (both 2016)

Start / End of a Period

startOf/endOf snap a date to the boundary of its day, month, or year — endOf('year') correctly returns Pagume 6 in leap years and Pagume 5 otherwise:

const date = new Kenat('2016/5/15');

date.startOfMonth().getEthiopian(); // → { year: 2016, month: 5, day: 1 }
date.endOfMonth().getEthiopian();   // → { year: 2016, month: 5, day: 30 }

date.startOf('year').getEthiopian(); // → { year: 2016, month: 1, day: 1 }

new Kenat('2015/5/1').endOf('year').getEthiopian();
// → { year: 2015, month: 13, day: 6 }  (2015 is a leap year, so Pagume has 6 days)

Date Difference & Distance API

const a = new Kenat('2015/5/15');
const b = new Kenat('2012/5/15');

// Precise differences
console.log(a.diffInDays(b));    // → 1095
console.log(a.diffInYears(b));   // → 3

// Human-friendly distance
console.log(a.distanceTo(b, { units: ['years', 'months', 'days'], output: 'string' }));
// → "2 years 9 months 3 days"

// Distance from today to a given date
console.log(new Kenat('2018/1/1').distanceFromToday({ output: 'string' }));

Calendar Generation

// Monthly calendar
const calendar = Kenat.getMonthCalendar(2017, 1, { 
  useGeez: false, 
  weekdayLang: 'amharic' 
});

// Yearly calendar
const yearCalendar = Kenat.getYearCalendar(2017);

// Date range generation
const start = new Kenat('2017/1/1');
const end = new Kenat('2017/1/10');
const range = Kenat.generateDateRange(start, end);

// Print the current month as a grid to the console
new Kenat().printThisMonth();

Fasting Periods

import { getFastingPeriod, getFastingInfo } from 'kenat';

// Get Lent fasting period
const lent = getFastingPeriod('ABIY_TSOME', 2017);
console.log(lent);
// → { start: { year: 2017, month: 7, day: 16 }, end: { year: 2017, month: 8, day: 12 } }

// Get fasting information
const fastingInfo = getFastingInfo('NINEVEH', 2017);

Holiday Distance Helpers

import { HolidayNames } from 'kenat';

// Distance to next holiday
console.log(Kenat.distanceToHoliday(HolidayNames.fasika, { 
  direction: 'future', 
  units: ['days'], 
  output: 'string' 
}));
// → "358 days"

Geez Numerals & Formatting

import { toGeez } from 'kenat';

console.log(toGeez(2017)); // → "፳፻፲፯"

// Format in Geez
const date = new Kenat('2017/1/1');
console.log(date.formatInGeezAmharic()); // → "መስከረም ፩ ፳፻፲፯"

Calendar Preference (Ethiopian / Gregorian)

If your app lets end users choose between the Ethiopian and Gregorian calendar, pass calendar: 'gregorian' to format(), toString(), toISOString(), or getDate() instead of branching with if/else at every call site:

const date = new Kenat('2016/1/1');
const userPref = 'gregorian'; // e.g. from a user setting

date.format({ calendar: userPref });      // → "September 12, 2023"
date.getDate({ calendar: userPref });     // → { year: 2023, month: 9, day: 12 }
date.toISOString({ calendar: userPref }); // → "2023-09-12T06:00" (standard ISO 8601)

// Defaults to 'ethiopian' when omitted
date.format(); // → "መስከረም 1 2016"

toISOString({ calendar: 'gregorian' }) converts Kenat's Ethiopian 12-hour time to Gregorian 24-hour time (12:00 day → 06:00) and never appends the non-standard +12h suffix that the default Ethiopian-calendar ISO string uses for night times — the result is a genuine, parser-safe ISO 8601 string.

Time Handling

// Set Ethiopian time (12-hour system)
const withTime = new Kenat('2017/1/1').setTime(8, 30, 'day');
console.log(withTime.format({ includeTime: true }));
// → "2017/1/1 8:30 day"

// Convert to ISO format
console.log(withTime.toISOString());
// → "2017-01-01T08:30"

Serialization

Kenat instances serialize cleanly with JSON.stringify via a built-in toJSON():

const date = new Kenat('2017/1/15');

console.log(date.toJSON());
// → {
//     ethiopian: { year: 2017, month: 1, day: 15 },
//     gregorian: { year: 2024, month: 9, day: 25 },
//     time: { hour: 12, minute: 0, period: 'day' }
//   }

console.log(JSON.stringify({ createdAt: date }));
// → '{"createdAt":{"ethiopian":{...},"gregorian":{...},"time":{...}}}'

📊 API Reference

Core Classes

Kenat (Default Export)

Main class for Ethiopian date operations.

Constructor:

new Kenat()                    // Current date
new Kenat('2017/1/1')         // Ethiopian date string
new Kenat({year: 2017, month: 1, day: 1}) // Date object
new Kenat(new Date())         // Gregorian Date object

Access & Conversion

  • getEthiopian() - Returns {year, month, day}
  • getGregorian() - Returns Gregorian equivalent
  • getDate({ calendar }) - Returns the date in 'ethiopian' (default) or 'gregorian', no if/else needed
  • getCurrentTime() - Returns the instance's Time object
  • setTime(hour, minute, period) - Returns a new instance with the given Ethiopian time

Formatting

  • format(options) - Format with various options, including lang, showWeekday, useGeez, includeTime, and { calendar: 'ethiopian' | 'gregorian' }
  • toString(options) - String representation of date + time; also accepts { calendar }
  • formatInGeezAmharic() - Amharic month name with Geez numerals
  • formatWithWeekday(lang, useGeez) - Formatted string including the weekday name
  • formatShort() - Compact "yyyy/mm/dd" format
  • toISOString(options) - ISO-style date string; { calendar: 'gregorian' } returns a standard ISO 8601 date
  • toJSON() - Plain-object representation for JSON.stringify

Comparison

  • isBefore(other) / isAfter(other) - Chronological comparison
  • isSameDay(other) / isSameMonth(other) / isSameYear(other) - Granular equality checks
  • isLeapYear() - Whether the instance's Ethiopian year is a leap year
  • weekday() - Day-of-week index (0 = Sunday)

Arithmetic & Period Boundaries

  • add(amount, unit) / subtract(amount, unit) - Chainable arithmetic (unit: 'days'|'months'|'years')
  • addDays(n) / addMonths(n) / addYears(n) - Direct arithmetic shortcuts
  • startOf(unit) / endOf(unit) - Snap to the start/end of 'day', 'month', or 'year' (leap-year aware)
  • startOfMonth() / endOfMonth() - Shortcuts for startOf('month') / endOf('month')
  • diffInDays(other) / diffInMonths(other) / diffInYears(other) - Precise numeric differences
  • distanceTo(other, options) - Human-friendly breakdown or string ({ units, output, lang })
  • distanceFromToday(options) - Distance from today to this instance

Holidays & Liturgical Calendar

  • isHoliday(options) - Check if the date is a holiday
  • getBahireHasab() - Get liturgical calculations for the instance's year

Calendar Grids

  • getMonthCalendar(year, month, useGeez) - Instance-level month grid (defaults to the instance's own month)
  • printThisMonth(useGeez) - Pretty-print the current month's calendar grid to the console

Static Helpers

  • Kenat.now() - Same as new Kenat()
  • Kenat.getMonthCalendar(year, month, options) - Generate a month calendar
  • Kenat.getYearCalendar(year, options) - Generate a full year's calendar
  • Kenat.generateDateRange(start, end) - Array of Kenat instances between two dates
  • Kenat.distanceToHoliday(holidayKey, options) - Distance to a holiday occurrence
  • Kenat.formatDistance(breakdown, options) - Format a distance breakdown as a human string

Utility Functions

Date Conversion

  • toEC(year, month, day) - Gregorian to Ethiopian
  • toGC(year, month, day) - Ethiopian to Gregorian
  • toGeez(number) - Convert to Geez numerals
  • toArabic(geezString) - Convert from Geez numerals

Holiday System

  • getHolidaysForYear(year, options) - Get all holidays for a year
  • getHolidaysInMonth(year, month, lang) - Get holidays for a month
  • getHoliday(key, year) - Get a specific holiday
  • HolidayTags - Constants for filtering holidays
  • HolidayNames - Constants for holiday keys

Fasting & Religious Calendar

  • getFastingPeriod(fastKey, year) - Get fasting period dates
  • getFastingInfo(fastKey, year) - Get fasting information
  • getFastingDays(fastKey, year) - Get the list of individual fasting days
  • getBahireHasab(year) - Get Bahire Hasab calculations

Calendar Generation

  • Kenat.getMonthCalendar(year, month, options) - Generate month calendar
  • Kenat.getYearCalendar(year, options) - Generate year calendar
  • Kenat.generateDateRange(start, end) - Generate date range
  • MonthGrid.create(options) - Create calendar grid

Distance & Arithmetic

  • diffBreakdown(dateA, dateB, options) - Precise date difference
  • Kenat.distanceToHoliday(holidayKey, options) - Distance to holiday

Constants

  • HolidayTags - Holiday category tags
  • HolidayNames - Holiday name constants
  • monthNames - Month name arrays in multiple languages (includes an English gregorian set)
  • FastingKeys - Fasting period keys

For detailed method signatures and advanced usage, refer to the full documentation.

🧱 Contribution Guide

  • Fork the repo & clone it.

  • Create a new branch:

    git checkout -b feature/your-feature
    
  • Write your changes (in src/*.ts) and add tests in the /tests directory.

  • Run npm run typecheck and npm test to ensure everything passes.

  • If you're changing anything in examples/, run npm run build first — the examples import from dist/, not src/.

  • Open a Pull Request with your improvements or bug fix.

👨‍💻 Author

Melaku Demeke

Acknowledgments

Special thanks to the Ethiopian Orthodox Tewahedo Church for preserving the traditional Bahire Hasab calculations and to the open-source community for their contributions and feedback.

🙌 Contributors

Thanks to all the amazing people who have contributed to this project!

Contributors

📄 License

MIT — see LICENSE for details.

Keywords

ethiopian

FAQs

Package last updated on 11 Jul 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts