flutter_ethiopian_date_picker
A customizable Material 3 Ethiopian (Ge'ez) date picker for Flutter with accurate Gregorian conversion, date-range selection, localization, theming, and seamless form integration.
Why flutter_ethiopian_date_picker?
- Native Ethiopian (Ge'ez) calendar support
- Accurate Gregorian ⇄ Ethiopian conversion
- Material 3–styled date picker
- Embeddable calendar widget
- Date range selection
- Form integration
- Full localization support
- Customizable theming
- Keyboard and screen-reader accessible
- Ethiopian Orthodox, Islamic, national, and cultural calendar events
Screenshots
![]() Example app — home |
![]() Date picker — default theme |
![]() Range picker — selected range |
![]() Date picker — custom theme (deep orange) |
More examples (dark theme, Amharic, Afaan Oromo, Tigrinya)
![]() Example app — dark theme |
![]() Localized — Amharic (አማርኛ) |
![]() Localized — Afaan Oromo, with keyboard-focus tooltip |
![]() Localized — Tigrinya (ትግርኛ) |
Installation
dependencies:
flutter_ethiopian_date_picker: ^1.1.0
flutter pub get
import 'package:flutter_ethiopian_date_picker/flutter_ethiopian_date_picker.dart';
Quick start
Show a date picker with the default configuration:
final date = await showEthiopianDatePicker(context: context);
Customization
final date = await showEthiopianDatePicker(
context: context,
initialDate: EthiopianDate.today(),
firstDate: EthiopianDate(2010, 1, 1),
lastDate: EthiopianDate(2020, 13, 5),
locale: EthiopianLocale.amharic.code,
theme: EthiopianDatePickerTheme.material3(context).copyWith(
primaryColor: Colors.deepOrange,
selectedColor: Colors.deepOrange,
backgroundColor: Colors.white,
),
);
EthiopianDatePickerThemehas no lightweight constructor — every field (includingonSelectedColor,todayBorderColor,disabledColor) is required. Build a custom theme by calling.material3(context)for the Material 3 defaults, then.copyWith(...)the colors you want to change.
Range selection
final range = await showEthiopianDateRangePicker(
context: context,
firstDate: EthiopianDate(2010, 1, 1),
lastDate: EthiopianDate(2020, 13, 5),
);
if (range != null) {
print('${range.start} → ${range.end}');
}
Converting between calendars
final ethiopian = EthiopianDate.fromGregorian(DateTime.now());
final gregorian = ethiopian.toGregorian();
// DateTime extension
final today = DateTime.now().toEthiopianDate();
Embedded calendar
class MyEmbeddedCalendar extends StatefulWidget {
const MyEmbeddedCalendar({super.key});
@override
State<MyEmbeddedCalendar> createState() => _MyEmbeddedCalendarState();
}
class _MyEmbeddedCalendarState extends State<MyEmbeddedCalendar> {
EthiopianDate _displayedMonth = EthiopianDate.today();
EthiopianDate? _selectedDate;
@override
Widget build(BuildContext context) {
return EthiopianCalendarView(
displayedMonth: _displayedMonth,
firstDate: EthiopianDate(2010, 1, 1),
lastDate: EthiopianDate(2020, 13, 5),
selectedDate: _selectedDate,
onDateSelected: (date) => setState(() => _selectedDate = date),
onMonthChanged: (month) => setState(() => _displayedMonth = month),
);
}
}
EthiopianCalendarView is fully stateless and controlled. The parent owns the displayed month and selected date (or selected range, which takes priority over selectedDate if both are set) and updates them through onMonthChanged and onDateSelected. It integrates naturally with setState, Provider, Riverpod, Bloc, or any other state management solution.
Form field usage
Form(
key: _formKey,
child: EthiopianDateFormField(
firstDate: EthiopianDate(2010, 1, 1),
lastDate: EthiopianDate(2020, 13, 5),
decoration: const InputDecoration(labelText: 'Birth date'),
validator: (value) => value == null ? 'Required' : null,
onSaved: (value) => _birthDate = value,
),
)
Localization
showEthiopianDatePicker(
context: context,
locale: EthiopianLocale.oromo.code,
);
Supported locales:
- English (
en) - Amharic (
am) - Afaan Oromo (
om) - Tigrinya (
ti)
Unsupported locale codes automatically fall back to English.
Theming
Pass an EthiopianDatePickerTheme to override primaryColor, selectedColor,
backgroundColor, spacing, and typography. With no theme provided, the picker
uses Material 3 defaults derived from the ambient Theme.of(context).
Calendar events
Since v1.1.0, the package includes a calendar events system covering Ethiopian Orthodox feasts and fasting seasons, Islamic holidays, national and international observances, and regional cultural/traditional events.
final service = CalendarService();
// All events for a given Ethiopian year.
final events = service.getEventsForYear(2018);
// Public holidays only.
final holidays = service.getPublicHolidays(ethiopianYear: 2018);
// Events on a specific date.
final today = service.getEventsForDate(EthiopianDate.today());
Every query returns EventOccurrences, not bare events — because not every
event has a calculable date. Some regional and traditional events (e.g.
Hamer Bull Jumping, Gamo Meskel) are community- or externally-determined,
and the package deliberately never fabricates a date for them. Check
occurrence.hasDate before reading occurrence.date:
for (final occurrence in service.getCulturalEvents(ethiopianYear: 2018)) {
final name = occurrence.event.translations.forLocale('en');
if (occurrence.hasDate) {
print('$name: ${occurrence.date}');
} else {
print('$name: date not available');
}
}
Full API reference for the events system (
CalendarEvent,EventOccurrence,CalendarTranslation,CalendarService, all supported event categories) is on the way — seeCHANGELOG.mdfor the current list of supported query methods in the meantime.
API reference
| API | Description |
|---|---|
EthiopianDate |
Core date model: year, month, day, validation, today(), comparisons (compareTo, isBefore, isAfter, isAtSameMomentAs), toJson/fromJson. |
EthiopianDate.fromGregorian(DateTime) |
Convert a DateTime to EthiopianDate. |
EthiopianDate.toGregorian() |
Convert back to a Gregorian DateTime. |
DateTime.toEthiopianDate() |
Extension method, equivalent to EthiopianDate.fromGregorian. |
showEthiopianDatePicker({...}) |
Opens the picker dialog, returns Future<EthiopianDate?>. null on cancel. |
showEthiopianDateRangePicker({...}) |
Opens the range picker dialog, returns Future<EthiopianDateRange?>. |
EthiopianDateRange |
start, end date pair. |
EthiopianCalendarView |
Embeddable, stateless calendar grid widget. Required: displayedMonth, firstDate, lastDate, onDateSelected, onMonthChanged. Optional: selectedDate, selectedRange (takes priority over selectedDate), locale, theme. |
EthiopianDateFormField |
FormField<EthiopianDate> — works with standard Form/FormState. |
EthiopianDatePickerTheme |
Visual customization: colors, spacing, typography. |
EthiopianLocale |
en, am, om, ti — enum used for all localized text. |
CalendarEvent |
A single calendar event/observance: translations, eventType, category, calendarSystem, dateRule. |
EventOccurrence |
A resolved (or unresolved) occurrence of an event for a given year — hasDate, date, isRange, rangeStart/rangeEnd, resolutionStatus. Every CalendarService query returns these, never bare CalendarEvents. |
CalendarTranslation |
Locale-keyed display names for a CalendarEvent — forLocale(code) returns the name for that locale, falling back to English if missing. |
CalendarService |
Query layer for events — getEventsForYear, getEventsForDate, getEventsForMonth, getUpcomingEvents, getPublicHolidays, getOrthodoxEvents, getIslamicEvents, and more. |
For complete API documentation, see the package page on pub.dev.
Features
- ✅ Gregorian ⇄ Ethiopian conversion (leap years, Pagume 5/6 days), fuzz-tested
- ✅ Material 3 date picker dialog
- ✅ Embeddable calendar widget
- ✅ Date range selection (same-day, cross-month, cross-year)
- ✅ Material 3 theming with full override support
- ✅ Localization: English, Amharic, Afaan Oromo, Tigrinya (fallback to English)
- ✅
Form/FormStateintegration viaEthiopianDateFormField - ✅ Accessibility: semantic labels, full keyboard navigation, ≥48px touch targets, screen reader smoke-tested (VoiceOver/TalkBack)
- ✅ No internal global/static mutable state — safe with Provider, Riverpod, and Bloc
- ✅ Golden-tested UI across all themes and locales
- ✅ Slide/fade month transitions, ripple selection, and dialog animations
- ✅ Verified building on Android, iOS, Web, Windows, macOS, and Linux
- ✅ Calendar events: Ethiopian Orthodox, Islamic, national, international, African, Beta Israel, cultural, and traditional observances, with no fabricated dates for externally-determined events
Example app
The example/ application demonstrates:
- Date picker dialog
- Embedded calendar widget
- Range selection
- Theme switching
- Locale switching
- Form integration
cd example
flutter pub get
flutter run
Contributing / development
Contributions, bug reports, and feature requests are welcome.
flutter analyzeandflutter testmust pass before opening a PR (enforced in CI).- Any change to the public API must update
CHANGELOG.md.
License
MIT — see the LICENSE file for details.
Libraries
- core/ethiopian_date
- core/ethiopian_date_arithmetic
- core/ethiopian_date_interop
- core/ethiopian_date_range
- core/ethiopian_date_range_selection
- core/jdn_converter
- flutter_ethiopian_date_picker
- Ethiopian (Ge'ez) calendar support for Dart & Flutter: an immutable date model, exact Gregorian conversion, date arithmetic, and a Material date picker widget.
- localization/am
- localization/en
- localization/ethiopian_locale
- localization/om
- localization/ti
- theme/picker_theme
- ui/calendar_view
- ui/date_picker_dialog
- ui/date_range_picker_dialog
- ui/day_cell
- ui/form_field
- ui/header
- utils/date_utils







