Ponjika

A pure Dart toolkit for the Bangladesh revised civil Bangla calendar. Typed dates, reverse conversion, strict parsing, formatting, arithmetic, recurrences and JSON DTOs. Flutter widgets are in ponjika_flutter.

Install

dependencies:
  ponjika: ^2.0.0
import 'package:ponjika/ponjika.dart';

final date = BanglaDate.fromGregorian(DateTime(2025, 4, 17));
final text = BanglaDateFormat('d MMMM, yyyy (EEEE) • SSSS').format(date);
// ৪ বৈশাখ, ১৪৩২ (বৃহস্পতিবার) • গ্রীষ্ম
final gregorian = date.toGregorian(); // UTC-encoded Gregorian civil date
final parsed = BanglaDateFormat.iso().parse('1432-01-04');

Calendar contract

Ruleset bd-revised-2019-v1: April 14 starts Boishakh; first six months have 31 days; Kartik–Magh and Choitro have 30; Falgun has 29, or 30 when its containing Gregorian year is leap (Bangla year +594).

Years 1–9405 are supported. Rules are proleptic before 2019 and are not historical or astronomical calendar reconstruction. Sunrise, West Bengal calendar variants, tithi and official holiday datasets are not implemented. Calendar seasons are month-pair labels rather than weather predictions.

Civil date or instant?

const calendar = BanglaCalendar();
// Reads date components exactly; does not shift for a timezone.
final civil = calendar.fromGregorian(DateTime(2025, 4, 14));
// Converts an instant to Bangladesh civil time explicitly.
final bangladesh = calendar.fromInstant(
  DateTime.utc(2025, 4, 13, 18),
  utcOffset: const Duration(hours: 6),
);
final today = calendar.today(utcOffset: const Duration(hours: 6));
final deterministic = calendar.today(clock: () => DateTime(2025, 4, 14));
final explanation = calendar.explain(DateTime(2025, 4, 14));

toGregorian() returns date components represented as UTC midnight, not a local-midnight instant. Resolve IANA/DST offsets externally for fromInstant.

Formatting and parsing

Token Meaning
yyyy Four-digit year
yy Two-digit year, formatting only
MMMM Full Bangla month name or English transliteration
MM, M Padded/unpadded numeric month
dd, d Padded/unpadded day
EEEE Full weekday
SSSS Full season
[text] Literal text
final format = BanglaDateFormat(
  'dd MMMM yyyy',
  language: PonjikaLanguage.bangla,
  numerals: PonjikaNumerals.latin,
);
final label = format.format(BanglaDate(1432, 1, 4)); // 04 বৈশাখ 1432
final date = format.tryParse('০৪ বৈশাখ ১৪৩২');
final amount = '123.45'.toBanglaDigits();

Parsing accepts either digit script, is strict about pattern and date validity, checks weekday/season when supplied, and requires a full year, month and day. parse throws FormatException; tryParse returns null.

Arithmetic and grids

final next = BanglaDate(1432, 6, 31).addMonths(1); // 1432-07-30
final strict = BanglaDate(1432, 1, 1).addYears(1, overflow: DateOverflow.reject);
final range = BanglaDateRange(start: next, end: next.addDays(6));
final days = range.dates; // inclusive, lazy
final cells = const BanglaCalendar().monthGrid(1432, 1, firstWeekday: DateTime.saturday);

Month/year arithmetic clamps by default. Reject mode throws if the destination date is invalid. Grids always contain 42 cells; adjacent dates outside supported years are null. All date construction and arithmetic validate supported bounds. Dates support equality, hashCode, comparison, copyWith and differenceInDays.

Recurring events

final birthday = BanglaAnnualEvent(
  id: 'birthday', title: 'Birthday', month: 11, day: 30,
  missingDatePolicy: MissingDatePolicy.skip,
);
final next = birthday.nextOccurrence(BanglaDate(1431, 1, 1));

Missing dates can skip, clamp, or reject. A recurrence only computes dates; it does not create OS notifications or imply a government holiday.

JSON boundary

final dto = BanglaDateDto.fromDomain(BanglaDate(1432, 1, 4));
final json = dto.toJson();
final restored = BanglaDateDto.fromJson(json).toDomain();

Generated json_serializable code is included. The DTO carries year, month, day and ruleset. Domain conversion validates dates and rejects unknown rulesets. No state-management dependency is required.

Compatibility

Ponjika.format and getSeasonEmoji remain available with legacy DD/MM/YY/WW/SS tokens. In 2.0, MM still means month name in that facade only. Midnight is now the default; explicit sunrise throws. WW/SS no longer require flags. Conversion results change because timezone shifting, boundaries and month rules are corrected.

Apache-2.0. See LICENSE.

Libraries

ponjika
Bangladesh revised civil calendar utilities, with no Flutter dependency.