DEV Community

Cover image for A Date Is Never Just a Date: From West Bengal's Panjika to a Bengali Calendar Library for Java 21
tapadyuti chatterjee
tapadyuti chatterjee

Posted on

A Date Is Never Just a Date: From West Bengal's Panjika to a Bengali Calendar Library for Java 21

LocalDate.of(2024, 4, 14) looks innocent enough.

Ask Java what day it represents and the answer is easy. Ask what Bengali date it represents, and a more interesting question appears:

Which Bengali calendar system do you mean?

That question is exactly why I built bengali-calendar, a Java 21 library for converting between Gregorian and Bengali dates while making the selected calendar convention explicit. Version 1.0.0 provides West Bengal Traditional and Bangladesh Revised modes; the precise scope of the latter is explained below.

I am from West Bengal, India, so this subject is personal to me. Bengali dates are not an abstract alternative numbering system that I discovered while designing an API. They were already present in the panjika at home, in the arrival of Poila Boishakh, in shopkeepers' haal khata, in the six seasons, and in the familiar question many families in West Bengal ask: When is Pujo this year?

This library grew from the wish to represent part of that lived culture in Java without pretending that one Bengali calendar convention speaks for every Bengali community.

Cover illustration: AI-generated and inspired by the Patua/Patachitra tradition of West Bengal; it is not presented as artisan-made traditional work.

Version 1.0.0 is now available on Maven Central:
https://central.sonatype.com/artifact/com.tapadyuti/bengali-calendar/overview

<dependency>
    <groupId>com.tapadyuti</groupId>
    <artifactId>bengali-calendar</artifactId>
    <version>1.0.0</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

This post is about what the library does and how to use it. I will not go deep into the implementation because I have not opened the source repository for contributions yet. But there is plenty to explore from the public API alone.

TL;DR

If you are already reaching for the copy button:

import com.tapadyuti.bengalicalendar.*;
import java.time.LocalDate;

BengaliDate date = BengaliCalendar.from(
    LocalDate.of(2024, 4, 14),
    BengaliCalendarSystem.WEST_BENGAL_TRADITIONAL
);

System.out.println(
    date.format("dd MMMM yyyy E", BengaliLocale.BENGALI)
);

// ০১ বৈশাখ ১৪৩১ WB
Enter fullscreen mode Exit fullscreen mode

The library provides:

  • Gregorian to Bengali conversion
  • Bengali to Gregorian conversion
  • WEST_BENGAL_TRADITIONAL and BANGLADESH_REVISED systems, with the version-specific compatibility note below
  • English and Bengali-script formatting
  • Bengali numeral parsing
  • Immutable date arithmetic
  • Year-month and date-range helpers
  • Bengali seasons, weekdays, and selected holidays
  • java.time interoperability through ChronoLocalDate and Chronology
  • Java 21 and JPMS support

Maven coordinates:

com.tapadyuti:bengali-calendar:1.0.0
Enter fullscreen mode Exit fullscreen mode

A calendar carries more than dates

Most of us meet calendars as grids: rows, columns, holidays, and perhaps a red circle around a deadline we are trying not to think about.

But calendars are also records of astronomy, agriculture, administration, language, and culture. The Bengali calendar is a particularly good example.

Historians do not agree on a single origin story. One historical tradition connects the Bengali era with Shashanka, ruler of Gauda in the early seventh century, and dates the beginning of the era to approximately 593–594 CE. Another influential account, recorded by Banglapedia, describes Mughal emperor Akbar promulgating a reformed calendar in 1584 and backdating it to his accession in 1556. According to that account, one practical concern was revenue collection: the Hijri calendar was lunar, while crops and harvests followed the solar year. The astronomer Fathullah Shirazi is associated with the effort to align the calendar with the agricultural cycle.

Even the month names carry traces of the sky. Banglapedia associates names such as Baishakh, Jyaistha, and Falgun with stars or constellations used in older calendrical traditions.

The story did not stop there. Calendars are living civic systems, and Bengali calendrical practice continued to evolve. Bangladesh adopted standardized civil rules following reform efforts associated with the Bangla Academy and the committee led by Muhammad Shahidullah, and revised its official civil calendar again in 2019. Many traditional panjikas used in West Bengal continue to determine month boundaries through astronomical solar transitions.

That history also shows why software should identify a calendar rule set precisely. Version 1.0.0 currently exposes these two modes:

  • West Bengal Traditional follows astronomical month boundaries associated with sankranti.
  • BANGLADESH_REVISED in version 1.0.0 follows the earlier standardized Bangladesh rules used before the 2019 revision.

Bangladesh compatibility note: The BANGLADESH_REVISED mode in version 1.0.0 should not be interpreted as the current post-2019 official Bangladesh civil calendar. Under the 2019 Bangla Academy reform reported by Prothom Alo, the first six months have 31 days, Falgun has 29 days—or 30 in a Gregorian leap year—and the remaining five months have 30 days. If your application requires current official Bangladesh civil dates, validate against an authoritative source; this version does not yet model that scheme separately.

Neither mode should be silently guessed by a programming library. The choice affects real output, particularly near month and year boundaries. So the selected rule set is part of the date's identity in this library.

BengaliDate date = BengaliCalendar.from(
    LocalDate.now(),
    BengaliCalendarSystem.WEST_BENGAL_TRADITIONAL
);

System.out.println(date.getCalendarSystem());

// WEST_BENGAL_TRADITIONAL
Enter fullscreen mode Exit fullscreen mode

That explicitness is intentional.

The West Bengal thread: Bangabda as a living calendar

In West Bengal, traditional calendrical practice remains woven into everyday cultural life. It is solar in structure, and month boundaries are connected to the Sun's movement from one zodiacal region to another—the transitions known as sankranti. This astronomical lineage is commonly associated with the Surya Siddhanta, a foundational Sanskrit work on astronomy. The traditional West Bengal convention therefore cannot be represented accurately as a simple fixed offset from the Gregorian calendar.

And then there is the panjika.

Calling a panjika a “calendar” is accurate, but incomplete. It has traditionally brought together dates, tithi, nakshatra, festivals, eclipses, auspicious times, and other information people use to organize religious and social life. Printed Bengali almanacs also became part of Bengal's wider print culture. Nineteenth-century editions could carry practical information ranging from fairs and holidays to postal rates, weights, measures, agriculture, and health. The panjika was not merely something hanging on a wall; it was a compact annual guide to the world.

That legacy remains visible in how many people in West Bengal experience the year. Poila Boishakh marks the Bengali New Year, and businesses may open a fresh haal khata, traditionally beginning a new ledger and renewing relationships with customers. Celebrations vary across families and communities; common practices include exchanging Shubho Noboborsho greetings, wearing new clothes, sharing sweets and festive meals, and, for some, visiting temples.

Traditional panjikas also help many communities determine the dates of observances such as Durga Puja, Kali Puja, Saraswati Puja, Jamai Shashthi, and Bhai Phonta. Many of these depend on tithi and other lunisolar or ritual calculations. To be clear, bengali-calendar is a date-conversion library, not a complete replacement for a traditional panjika or a general-purpose tithi engine. That boundary matters just as much as the features the library does provide.

For me, the West Bengal calendar carries memories as much as dates: the turn of a season, handwritten entries in a new calendar, the anticipation before Pujo, and the familiar Bengali month name that makes a Gregorian date feel closer to home.

Meet the twelve Bengali months

The Bengali year begins with Baishakh, not January, and runs through twelve months grouped into six traditional seasons. Each pair of months gives the year a different mood—from the heat of Grishma to the rain of Barsha, the clear skies of Sharat, and the colour of Basanta.

Gregorian ranges below are deliberately approximate. Exact boundaries can shift with the year and the chosen Bengali calendar system.

No. Bengali month Transliteration Season Rough Gregorian period
বৈশাখ Baishakh গ্রীষ্ম — Grishma (summer) April–May
জ্যৈষ্ঠ Jyaistha গ্রীষ্ম — Grishma (summer) May–June
আষাঢ় Ashadha বর্ষা — Barsha (monsoon) June–July
শ্রাবণ Shraban বর্ষা — Barsha (monsoon) July–August
ভাদ্র Bhadra শরৎ — Sharat (autumn) August–September
আশ্বিন Ashwin শরৎ — Sharat (autumn) September–October
কার্তিক Kartik হেমন্ত — Hemanta (late autumn) October–November
অগ্রহায়ণ Agrahayan হেমন্ত — Hemanta (late autumn) November–December
পৌষ Paush শীত — Shita (winter) December–January
১০ মাঘ Magh শীত — Shita (winter) January–February
১১ ফাল্গুন Falgun বসন্ত — Basanta (spring) February–March
১২ চৈত্র Chaitra বসন্ত — Basanta (spring) March–April

These names are not just labels. Baishakh opens the year with Poila Boishakh; Ashwin is inseparable in West Bengal from the anticipation of Durga Puja; Agrahayan carries the memory of the harvest; Paush evokes winter fairs and pithe-puli; Falgun arrives with spring colour; and Chaitra closes the year before the cycle begins again.

The library exposes the months in calendar order and in both scripts:

for (BengaliMonth month : BengaliMonth.values()) {
    System.out.printf(
        "%d. %s — %s%n",
        month.getValue(),
        month.getDisplayName(BengaliLocale.BENGALI),
        month.getDisplayName(BengaliLocale.ENGLISH)
    );
}

// 1. বৈশাখ — Baishakh
// 2. জ্যৈষ্ঠ — Jyaistha
// 3. আষাঢ় — Ashadha
// 4. শ্রাবণ — Shraban
// 5. ভাদ্র — Bhadra
// 6. আশ্বিন — Ashwin
// 7. কার্তিক — Kartik
// 8. অগ্রহায়ণ — Agrahayan
// 9. পৌষ — Paush
// 10. মাঘ — Magh
// 11. ফাল্গুন — Falgun
// 12. চৈত্র — Chaitra
Enter fullscreen mode Exit fullscreen mode

Why West Bengal Traditional is the default

If no calendar system is supplied, the library uses:

BengaliDate today = BengaliCalendar.today();

System.out.println(today.getCalendarSystem());
// WEST_BENGAL_TRADITIONAL
Enter fullscreen mode Exit fullscreen mode

I chose that default because I am from West Bengal and it is the convention closest to the context in which I experienced the Bengali calendar. It is a personal and documented default—not a claim that the West Bengal convention is more authentic, or that every Bengali application should use it.

Bengali-speaking communities in West Bengal and Bangladesh use distinct calendar conventions shaped by their own histories. Software should respect those differences by making the chosen system visible:

BengaliDate westBengalDate = BengaliCalendar.from(
    LocalDate.now(),
    BengaliCalendarSystem.WEST_BENGAL_TRADITIONAL
);

BengaliDate bangladeshDate = BengaliCalendar.from(
    LocalDate.now(),
    BengaliCalendarSystem.BANGLADESH_REVISED
);

System.out.println(westBengalDate.getCalendarSystem());
System.out.println(bangladeshDate.getCalendarSystem());

// WEST_BENGAL_TRADITIONAL
// BANGLADESH_REVISED
Enter fullscreen mode Exit fullscreen mode

The default reflects where I come from. The API makes room for more than where I come from.

Installation

Maven

<dependency>
    <groupId>com.tapadyuti</groupId>
    <artifactId>bengali-calendar</artifactId>
    <version>1.0.0</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Gradle

implementation 'com.tapadyuti:bengali-calendar:1.0.0'
Enter fullscreen mode Exit fullscreen mode

The library requires Java 21 or later.

If your project uses JPMS, add:

requires com.tapadyuti.bengalicalendar;
Enter fullscreen mode Exit fullscreen mode

Your first conversion

The smallest useful example is a Gregorian-to-Bengali conversion:

In the examples below, lines beginning with // show the expected console output. Results based on LocalDate.now() are marked as variable.

import com.tapadyuti.bengalicalendar.BengaliCalendar;
import com.tapadyuti.bengalicalendar.BengaliCalendarSystem;
import com.tapadyuti.bengalicalendar.BengaliDate;

import java.time.LocalDate;

public class BengaliCalendarDemo {
    public static void main(String[] args) {
        LocalDate gregorian = LocalDate.of(2024, 4, 14);

        BengaliDate bengali = BengaliCalendar.from(
            gregorian,
            BengaliCalendarSystem.BANGLADESH_REVISED
        );

        System.out.println(bengali.getYear());       // 1431
        System.out.println(bengali.getMonth());      // BAISHAKH
        System.out.println(bengali.getDayOfMonth()); // 1
    }
}
Enter fullscreen mode Exit fullscreen mode

The conversion is bidirectional:

LocalDate original = LocalDate.of(2024, 4, 14);

BengaliDate bengali = BengaliCalendar.from(
    original,
    BengaliCalendarSystem.BANGLADESH_REVISED
);

LocalDate convertedBack = BengaliCalendar.toGregorian(bengali);

System.out.println(convertedBack); // 2024-04-14
Enter fullscreen mode Exit fullscreen mode

You can also ask for today's Bengali date:

BengaliDate today = BengaliCalendar.today();
System.out.println(
    today.format("dd MMMM yyyy E", BengaliLocale.ENGLISH)
);

// Output varies with the date; the final marker is WB by default.
Enter fullscreen mode Exit fullscreen mode

The default is WEST_BENGAL_TRADITIONAL. In reusable or shared code, I still recommend specifying the system when the distinction matters:

BengaliDate westBengalToday = BengaliCalendar.today(
    BengaliCalendarSystem.WEST_BENGAL_TRADITIONAL
);

BengaliDate bangladeshToday = BengaliCalendar.today(
    BengaliCalendarSystem.BANGLADESH_REVISED
);

System.out.println(westBengalToday.getCalendarSystem());
System.out.println(bangladeshToday.getCalendarSystem());

// WEST_BENGAL_TRADITIONAL
// BANGLADESH_REVISED
Enter fullscreen mode Exit fullscreen mode

One Gregorian date, two Bengali conventions

The two systems are deliberately represented by an enum:

LocalDate date = LocalDate.of(2024, 4, 14);

BengaliDate wb = BengaliCalendar.from(
    date,
    BengaliCalendarSystem.WEST_BENGAL_TRADITIONAL
);

BengaliDate bd = BengaliCalendar.from(
    date,
    BengaliCalendarSystem.BANGLADESH_REVISED
);

System.out.println(wb.getCalendarSystem()); // WEST_BENGAL_TRADITIONAL
System.out.println(bd.getCalendarSystem()); // BANGLADESH_REVISED
Enter fullscreen mode Exit fullscreen mode

This is more than metadata. A BengaliDate keeps its calendar system with it, so later operations know which rules to apply:

BengaliDate nextWeek = wb.plusDays(7);

System.out.println(nextWeek.getCalendarSystem());
// WEST_BENGAL_TRADITIONAL
Enter fullscreen mode Exit fullscreen mode

Configure an application-wide default

If your application consistently uses one convention, set it once during startup:

BengaliCalendar.setDefault(
    BengaliCalendarSystem.BANGLADESH_REVISED
);

BengaliDate today = BengaliCalendar.today();
BengaliDate converted = BengaliCalendar.from(LocalDate.now());

System.out.println(today.getCalendarSystem());
System.out.println(converted.getCalendarSystem());

// BANGLADESH_REVISED
// BANGLADESH_REVISED
Enter fullscreen mode Exit fullscreen mode

You can read the current default too:

BengaliCalendarSystem system = BengaliCalendar.getDefault();
System.out.println(system);

// BANGLADESH_REVISED
Enter fullscreen mode Exit fullscreen mode

For servers and containers, the same choice can be supplied as a JVM property:

java -Dbengalicalendar.default.system=BANGLADESH_REVISED -jar app.jar
Enter fullscreen mode Exit fullscreen mode

Accepted short forms are BD and WB.

Bengali numerals: ০ থেকে ৯

Bengali has its own decimal digits. They represent exactly the same values as Western digits; only the glyphs change.

Value Western digit Bengali digit
Zero 0
One 1
Two 2
Three 3
Four 4
Five 5
Six 6
Seven 7
Eight 8
Nine 9

So the Bengali year 1431 is written ১৪৩১, and 01 Baishakh 1431 becomes ০১ বৈশাখ ১৪৩১.

You do not need to replace the digits yourself. Selecting BengaliLocale.BENGALI makes the formatter use Bengali month names and Bengali numerals together:

BengaliDate pohelaBoishakh = BengaliDate.of(
    1431,
    BengaliMonth.BAISHAKH,
    1,
    BengaliCalendarSystem.WEST_BENGAL_TRADITIONAL
);

System.out.println(
    pohelaBoishakh.format("dd/MM/yyyy", BengaliLocale.ENGLISH)
);
System.out.println(
    pohelaBoishakh.format("dd/MM/yyyy", BengaliLocale.BENGALI)
);

// 01/01/1431
// ০১/০১/১৪৩১
Enter fullscreen mode Exit fullscreen mode

The same applies in reverse: the parser can read Bengali digits directly, so users do not have to transliterate their dates before submitting them.

Formatting in English and Bengali

A cultural date library should not stop at returning an enum and an integer.

Format a Bengali date in English:

BengaliDate date = BengaliDate.of(
    1431,
    BengaliMonth.BAISHAKH,
    1,
    BengaliCalendarSystem.WEST_BENGAL_TRADITIONAL
);

String english = date.format(
    "dd MMMM yyyy E",
    BengaliLocale.ENGLISH
);

System.out.println(english);
// 01 Baishakh 1431 WB
Enter fullscreen mode Exit fullscreen mode

Now format the same date in Bengali script and Bengali numerals:

String bengali = date.format(
    "dd MMMM yyyy E",
    BengaliLocale.BENGALI
);

System.out.println(bengali);
// ০১ বৈশাখ ১৪৩১ WB
Enter fullscreen mode Exit fullscreen mode

The formatter supports a compact set of familiar tokens:

Token Meaning
d Day without padding
dd Zero-padded day
M Month number
MM Zero-padded month number
MMM Abbreviated month name
MMMM Full month name
y Bengali year
yyyy Four-digit Bengali year
E Calendar-system abbreviation (BD or WB)

For example:

System.out.println(date.format("d/M/y"));
System.out.println(date.format("dd-MM-yyyy E"));
System.out.println(date.format("MMMM d, yyyy", BengaliLocale.ENGLISH));

// 1/1/1431
// 01-01-1431 WB
// Baishakh 1, 1431
Enter fullscreen mode Exit fullscreen mode

Parsing—including Bengali numerals

Formatting is only half the job. User input has to make the return journey.

Parse an English-numeral date:

BengaliDate parsed = BengaliDateFormatter.parse(
    "01-01-1431",
    "dd-MM-yyyy",
    BengaliCalendarSystem.BANGLADESH_REVISED,
    BengaliLocale.ENGLISH
);

System.out.println(
    parsed.format("dd MMMM yyyy E", BengaliLocale.ENGLISH)
);

// 01 Baishakh 1431 BD
Enter fullscreen mode Exit fullscreen mode

Or parse Bengali numerals directly:

BengaliDate parsedBengali = BengaliDateFormatter.parse(
    "০১-০১-১৪৩১",
    "dd-MM-yyyy",
    BengaliCalendarSystem.WEST_BENGAL_TRADITIONAL,
    BengaliLocale.BENGALI
);

System.out.println(
    parsedBengali.format("dd MMMM yyyy E", BengaliLocale.BENGALI)
);

// ০১ বৈশাখ ১৪৩১ WB
Enter fullscreen mode Exit fullscreen mode

Then convert the result into a regular Java date whenever you need to store, compare, or integrate it with another system:

LocalDate isoDate = parsedBengali.toGregorian();
System.out.println(isoDate);

// 2024-04-14
Enter fullscreen mode Exit fullscreen mode

Date arithmetic without manual month tables

Nobody should have to write a chain of if statements just to find “ten Bengali days from now.”

BengaliDate pohelaBoishakh = BengaliDate.of(
    1431,
    BengaliMonth.BAISHAKH,
    1,
    BengaliCalendarSystem.BANGLADESH_REVISED
);

BengaliDate tenDaysLater = pohelaBoishakh.plusDays(10);
BengaliDate nextMonth = pohelaBoishakh.plusMonths(1);
BengaliDate nextYear = pohelaBoishakh.plusYears(1);

BengaliDate previousDay = pohelaBoishakh.minusDays(1);

System.out.println(tenDaysLater.format("dd MMMM yyyy E"));
System.out.println(nextMonth.format("dd MMMM yyyy E"));
System.out.println(nextYear.format("dd MMMM yyyy E"));
System.out.println(previousDay.format("dd MMMM yyyy E"));

// 11 Baishakh 1431 BD
// 01 Jyaistha 1431 BD
// 01 Baishakh 1432 BD
// 30 Chaitra 1430 BD
Enter fullscreen mode Exit fullscreen mode

Comparisons are available directly:

if (tenDaysLater.isAfter(pohelaBoishakh)) {
    System.out.println("Time still works.");
}

// Time still works.
Enter fullscreen mode Exit fullscreen mode

Because BengaliDate implements ChronoLocalDate, it also participates in Java's temporal APIs:

long epochDay = pohelaBoishakh.toEpochDay();
long daysBetween = pohelaBoishakh.until(tenDaysLater, java.time.temporal.ChronoUnit.DAYS);

System.out.println(epochDay);
System.out.println(daysBetween);

// 19827
// 10
Enter fullscreen mode Exit fullscreen mode

Building a calendar UI

For a calendar grid, BengaliYearMonth avoids repeatedly reconstructing year and month information:

BengaliCalendar.setDefault(
    BengaliCalendarSystem.WEST_BENGAL_TRADITIONAL
);

BengaliYearMonth baishakh = BengaliYearMonth.of(
    1431,
    BengaliMonth.BAISHAKH
);

int daysInMonth = baishakh.lengthOfMonth();
BengaliDate twelfthDay = baishakh.atDay(12);

System.out.println(daysInMonth);
System.out.println(twelfthDay.format("dd MMMM yyyy E"));

// 31
// 12 Baishakh 1431 WB
Enter fullscreen mode Exit fullscreen mode

For inclusive intervals, use BengaliDateRange:

BengaliDate start = BengaliDate.of(
    1431,
    BengaliMonth.BAISHAKH,
    1,
    BengaliCalendarSystem.WEST_BENGAL_TRADITIONAL
);

BengaliDate end = start.plusDays(6);
BengaliDateRange firstWeek = BengaliDateRange.of(start, end);

System.out.println(firstWeek.lengthInDays()); // 7

firstWeek.stream()
    .map(d -> d.format("dd MMMM", BengaliLocale.BENGALI))
    .forEach(System.out::println);

// ০১ বৈশাখ
// ০২ বৈশাখ
// ০৩ বৈশাখ
// ০৪ বৈশাখ
// ০৫ বৈশাখ
// ০৬ বৈশাখ
// ০৭ বৈশাখ
Enter fullscreen mode Exit fullscreen mode

You can also ask whether a date belongs to a range:

boolean inside = firstWeek.contains(start.plusDays(3));
System.out.println(inside);

// true
Enter fullscreen mode Exit fullscreen mode

Seasons, weekdays, and selected holidays

The Bengali year is traditionally divided into six seasons, each associated with two months. That relationship is available from a date:

BengaliSeason season = pohelaBoishakh.getSeason();

System.out.println(
    season.getDisplayName(BengaliLocale.BENGALI)
);

// গ্রীষ্ম
Enter fullscreen mode Exit fullscreen mode

Weekday names are available as well:

BengaliDayOfWeek weekday = pohelaBoishakh.getDayOfWeek();

System.out.println(
    weekday.getDisplayName(BengaliLocale.BENGALI)
);

// রবিবার
Enter fullscreen mode Exit fullscreen mode

And selected cultural holidays can be queried from a date:

pohelaBoishakh.getHoliday().ifPresent(holiday ->
    System.out.println(
        holiday.getDisplayName(BengaliLocale.ENGLISH)
    )
);

// Pohela Boishakh
Enter fullscreen mode Exit fullscreen mode

Or collected for a Bengali year and system:

Map<BengaliDate, BengaliHoliday> holidays =
    BengaliHoliday.forYear(
        1431,
        BengaliCalendarSystem.BANGLADESH_REVISED
    );

System.out.println(holidays.size());

// 3
Enter fullscreen mode Exit fullscreen mode

Holiday data should be treated as a cultural convenience, not as a replacement for an official legal or organizational holiday schedule.

Working with java.time.Chronology

For advanced integrations, the chronology can be resolved through Java's service-loading mechanism:

import java.time.chrono.Chronology;

Chronology bengali = Chronology.of("Bengali");

System.out.println(bengali.getId());           // Bengali
System.out.println(bengali.getCalendarType()); // bengali
Enter fullscreen mode Exit fullscreen mode

Or accessed directly:

BengaliChronology chronology = BengaliChronology.INSTANCE;
System.out.println(chronology.getId());

// Bengali
Enter fullscreen mode Exit fullscreen mode

Most applications will find BengaliCalendar and BengaliDate simpler. The chronology integration is there for code that already works generically with Java calendar systems.

A small testing detail that matters

“Today” is usually the enemy of deterministic tests. The library therefore accepts a Clock:

import java.time.Clock;
import java.time.Instant;
import java.time.ZoneOffset;

Clock fixedClock = Clock.fixed(
    Instant.parse("2024-04-14T00:00:00Z"),
    ZoneOffset.UTC
);

BengaliCalendar.setDefault(
    BengaliCalendarSystem.WEST_BENGAL_TRADITIONAL
);

BengaliDate predictableToday = BengaliCalendar.today(fixedClock);

System.out.println(
    predictableToday.format("dd MMMM yyyy E", BengaliLocale.ENGLISH)
);

// 01 Baishakh 1431 WB
Enter fullscreen mode Exit fullscreen mode

That lets application tests stay stable regardless of when or where they run.

What this library is—and what it is not

This library is intended to provide a practical Java API for:

  • application-level date conversion
  • locale-aware display and parsing
  • date arithmetic
  • calendar UI helpers
  • interoperability with java.time

It does not claim that the history or practice of Bengali calendrical computation can be reduced to one universally agreed table. Traditional almanacs, astronomical conventions, civil reforms, locations, and historical periods all matter.

For production code, choose the calendar system explicitly when the distinction has business or cultural significance. For historical research, religious observance, or legal use, validate results against an authoritative source for the relevant place and period.

That is not a weakness of the subject. It is the subject.

Why I built it

The first version began with a straightforward requirement: convert a Gregorian date into a Bengali date.

The requirement did not stay straightforward for long.

Once I considered the different calendar conventions used in West Bengal and Bangladesh, along with Bengali numerals, parsing, date arithmetic, seasons, holidays, ranges, and the java.time type system, it became clear that a converter function would not be enough. I wanted an API that felt natural to a Java developer without flattening the cultural differences it represents.

The result is intentionally familiar:

BengaliDate tomorrow = BengaliCalendar.today().plusDays(1);

System.out.println(
    tomorrow.format("dd MMMM yyyy E", BengaliLocale.ENGLISH)
);

// Output varies with the date; the final marker is WB by default.
Enter fullscreen mode Exit fullscreen mode

But it also keeps the important part visible:

BengaliDate current = BengaliCalendar.from(
    LocalDate.now(),
    BengaliCalendarSystem.WEST_BENGAL_TRADITIONAL
);

System.out.println(current.getCalendarSystem());

// WEST_BENGAL_TRADITIONAL
Enter fullscreen mode Exit fullscreen mode

Convenience where it helps; explicitness where it matters.

I am open to collaboration

The repository is not open for public contribution yet, but I am very open to conversations and collaboration around the project.

I would especially like to hear from:

  • Bengali calendar and panjika experts
  • historians and researchers working on West Bengal's calendrical and almanac traditions
  • developers from Bangladesh and West Bengal with real-world date examples
  • Java java.time and chronology specialists
  • localization and Bengali-language contributors
  • developers building calendar, cultural, education, or archival applications

Useful collaboration could include validating edge cases, comparing authoritative date tables, expanding tests, improving transliterations, refining cultural data, or shaping a future public contribution model.

If the library is useful to you—or if you find a date that deserves a closer look—leave a comment or reach out through my Dev.to profile. I would rather improve the library through informed discussion than pretend calendars are simpler than they are.

Links

If you try it, I would love to know what you build.

Top comments (0)