Parsi DateTime Picker
A complete Flutter package for Persian (Jalali/Shamsi) date and time picking, with support for Material and Cupertino design. Built on top of imperial_persian_date for accurate calendar conversion.
✨ Special Feature: All dates in the UI are displayed as Imperial Persian Calendar years (e.g. 2584).
✨ Features
- 📅 Material Date Picker — Beautiful Jalali calendar with month/year navigation
- 📆 Date Range Picker — Select start and end dates with visual range highlighting
- ⏰ Time Picker — Time selection with RTL support and Persian labels
- 🍎 Cupertino Picker — iOS-style picker (date, time, or combined)
- ⌨️ Text Input Mode — Direct date entry in
YYYY/MM/DDformat - 🎨 Material 3 Support — Modern design with dynamic color schemes
- 🔢 Persian Numerals — All numbers displayed in Persian digits (۱۲۳۴۵۶۷۸۹۰)
- 👑 Imperial Calendar — Year display in Imperial Persian format across all UIs
- 🎯 Holiday Display — Mark holidays in red
- 🚫 Disable Specific Days — Disable individual dates or specific weekdays
- 🌍 Multi-language Support — Persian, Dari, Kurdish, Pashto, and English
- 🎭 Full RTL Support — Complete right-to-left layout
- 🔄 Bidirectional Conversion — Seamless conversion between Gregorian, Shamsi, and Imperial calendars
📦 Installation
Add the following to your pubspec.yaml:
dependencies:
parsi_datetime_picker: ^0.0.2
flutter_localizations:
sdk: flutter
Then run:
flutter pub get
🚀 Quick Start
1. Setup Localization
Add localization delegates to your MaterialApp:
import 'package:flutter/material.dart';
import 'package:parsi_datetime_picker/parsi_datetime_picker.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Parsi Date Picker Example',
localizationsDelegates: parsiLocalizationsDelegates,
supportedLocales: parsiSupportedLocales,
locale: const Locale('fa', 'IR'),
home: const HomePage(),
);
}
}
2. Show the Date Picker
final ParsiDate? picked = await showParsiDatePicker(
context: context,
initialDate: ParsiDate.now(),
firstDate: ParsiDate(2560, 1, 1), // Imperial year 2560
lastDate: ParsiDate(2630, 12, 29), // Imperial year 2630
helpText: 'Select Date',
);
if (picked != null) {
print('Selected Imperial year: ${picked.imperialYear}'); // e.g. 2584
print('Internal Shamsi year: ${picked.year}'); // e.g. 1404
}
Important Note: The picker UI displays Imperial Persian years (e.g. 2584), while
ParsiDateinternally uses Shamsi years for calculations.
📖 Usage Examples
Material Date Picker
final ParsiDate? date = await showParsiDatePicker(
context: context,
initialDate: ParsiDate.now(),
firstDate: ParsiDate(2560, 1, 1),
lastDate: ParsiDate(2630, 12, 29),
// Optional: mark holidays (e.g. Nowruz)
holidayDates: [
ParsiDate(2584, 1, 1),
ParsiDate(2584, 1, 2),
ParsiDate(2584, 1, 3),
],
// Optional: disable specific days
selectableDayPredicate: (date) {
return date.weekDay != 7; // disable Fridays
},
// Optional: custom labels
helpText: 'Select Birthday',
cancelText: 'Cancel',
confirmText: 'Confirm',
);
Date Range Picker
final ParsiDateRange? range = await showParsiDateRangePicker(
context: context,
firstDate: ParsiDate(2560, 1, 1),
lastDate: ParsiDate(2630, 12, 29),
// Optional: initial range
initialDateRange: ParsiDateRange(
start: ParsiDate(2584, 6, 1),
end: ParsiDate(2584, 6, 10),
),
helpText: 'Select Date Range',
);
if (range != null) {
print('From ${range.start.imperialYear}/${range.start.month}/${range.start.day}');
print('To ${range.end.imperialYear}/${range.end.month}/${range.end.day}');
}
Time Picker
final TimeOfDay? time = await showParsiTimePicker(
context: context,
initialTime: TimeOfDay.now(),
helpText: 'Select Time',
);
if (time != null) {
print('Selected time: ${time.hour}:${time.minute}');
}
Cupertino Picker
class MyWidget extends StatefulWidget {
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
ParsiDate _selectedDate = ParsiDate.now();
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Date: ${_selectedDate.imperialYear}/${_selectedDate.month}/${_selectedDate.day}'),
SizedBox(
height: 200,
child: ParsiCupertinoDatePicker(
mode: ParsiCupertinoDatePickerMode.date,
initialDateTime: _selectedDate,
minimumDate: ParsiDate(2560, 1, 1),
maximumDate: ParsiDate(2630, 12, 29),
onDateTimeChanged: (date) {
setState(() => _selectedDate = date);
},
),
),
],
);
}
}
Text Input Mode
final ParsiDate? date = await showParsiDatePicker(
context: context,
initialDate: ParsiDate.now(),
firstDate: ParsiDate(2560, 1, 1),
lastDate: ParsiDate(2630, 12, 29),
initialEntryMode: ParsiDatePickerEntryMode.input,
);
Note: In input mode, users enter dates in Imperial Persian format:
YYYY/MM/DD(e.g. ۲۵۸۴/۰۶/۱۵)
🗓️ ParsiDate Class API
Constructors
ParsiDate(2584, 6, 15) // Specific date
ParsiDate.now() // Today
ParsiDate.fromDateTime(DateTime(2025, 9, 6)) // From Gregorian
Properties
final date = ParsiDate(2584, 6, 15);
date.year // 2584
date.month // 6 (1–12)
date.day // 15 (1–31)
date.hour // 0–23
date.minute // 0–59
date.second // 0–59
date.monthName // 'شهریور'
date.monthNameEn // 'Shahrivar'
date.weekDayName // 'سهشنبه'
date.weekDay // 1–7 (1=Saturday, 7=Friday)
date.isLeapYear // true/false
date.monthLength // 29–31
date.imperialYear // 2584
Conversion Methods
DateTime gregorian = date.toDateTime();
ParsiDate parsi = DateTime.now().toParsiDate();
Date Arithmetic
final date = ParsiDate(2584, 6, 15);
date.addDays(5) // 2584/6/20
date.addDays(-10) // 2584/6/5
date.addMonths(2) // 2584/8/15
date.addMonths(-1) // 2584/5/15
date.addYears(1) // 2585/6/15
date.copyWith(year: 2585, month: 7, day: 20)
Date Comparison
final date1 = ParsiDate(2584, 6, 15);
final date2 = ParsiDate(2584, 7, 1);
date1.isBefore(date2) // true
date1.isAfter(date2) // false
date1.isAtSameMomentAs(date2) // false
date1.isSameDay(date2) // false
date1.difference(date2) // -16
date1.compareTo(date2) // -1
Formatting
final date = ParsiDate(2584, 6, 15, hour: 14, minute: 30);
date.format('WWWW، DD MMMM YYYY') // سهشنبه، ۱۵ شهریور ۲۵۸۴
date.format('DD/MM/YYYY') // ۱۵/۰۶/۲۵۸۴
date.format('YYYY/MM/DD') // ۲۵۸۴/۰۶/۱۵
date.format('YYYY/MM/DD HH:mm') // ۲۵۸۴/۰۶/۱۵ ۱۴:۳۰
Format Tokens
| Token | Description | Example |
|---|---|---|
YYYY |
4-digit year (Imperial Persian) | ۲۵۸۴ |
YY |
2-digit year (Imperial Persian) | ۸۴ |
MMMM |
Full month name (Persian) | شهریور |
MMM |
Month name (English) | Shahrivar |
MM |
Zero-padded month (01–12) | ۰۶ |
M |
Month number (1–12) | ۶ |
DD |
Zero-padded day (01–31) | ۱۵ |
D |
Day number (1–31) | ۱۵ |
WWWW |
Full weekday name (Persian) | سهشنبه |
HH |
Hour (00–23) | ۱۴ |
mm |
Minute (00–59) | ۳۰ |
ss |
Second (00–59) | ۰۵ |
🌍 Calendar Systems
This package supports three calendar systems:
1. Shamsi (Solar Hijri / Jalali)
The official calendar of Iran and Afghanistan. Used internally for calculations.
- Year 1 = 622 AD (Hijra)
- Example: ۱۴۰۴/۰۶/۱۵
2. Gregorian
The international standard calendar.
- Example: 2025-09-06
3. Imperial Persian ⭐
Iran's historical calendar based on the coronation of Cyrus the Great.
- Year 1 = 559 BC
- Conversion: Imperial year = Shamsi year + 1180
- Displayed in all UI components
- Example: ۲۵۸۴/۰۶/۱۵
Calendar Conversion Examples
final date = ParsiDate(2584, 6, 15);
print('Imperial: ${date.imperialYear}'); // 2584
print('Gregorian: ${date.toDateTime()}'); // 2025-09-06
print(date.format('YYYY/MM/DD')); // ۲۵۸۴/۰۶/۱۵
Why Imperial Persian?
The Imperial Persian calendar honors Iran's ancient heritage:
- Year 1 marks the coronation of Cyrus the Great (559 BC)
- Year 2500 (1971 AD) was celebrated under Mohammad Reza Shah Pahlavi
- Current year 2584 = Shamsi 1404 = Gregorian 2025
This package displays Imperial years across all UI components while keeping Shamsi calculations internally for compatibility.
🎨 Customization
Custom Theme
Pickers automatically adapt to your app's theme:
MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
useMaterial3: true,
),
)
Custom Labels
await showParsiDatePicker(
context: context,
initialDate: ParsiDate.now(),
firstDate: ParsiDate(2560, 1, 1),
lastDate: ParsiDate(2630, 12, 29),
helpText: 'Please select a date',
cancelText: 'Close',
confirmText: 'Confirm',
);
📱 Platform Support
| Platform | Supported |
|---|---|
| Android | ✅ |
| iOS | ✅ |
| Web | ✅ |
| macOS | ✅ |
| Windows | ✅ |
| Linux | ✅ |
💡 Practical Tips
Working with Imperial Years
final birthDate = ParsiDate(2550, 3, 15);
print('Birth date: ${birthDate.imperialYear}/${birthDate.month}/${birthDate.day}');
// Output: Birth date: 2550/3/15
Quick Conversion Table
| Shamsi Year | Imperial Year | Gregorian Year |
|---|---|---|
| ۱۳۰۰ | ۲۴۸۰ | 1921 |
| ۱۳۵۷ | ۲۵۳۷ | 1978 |
| ۱۴۰۰ | ۲۵۸۰ | 2021 |
| ۱۴۰۴ | ۲۵۸۴ | 2025 |
| ۱۴۵۰ | ۲۶۳۰ | 2071 |
🤝 Contributing
Contributions are welcome! Feel free to open a Pull Request.
📄 License
This project is licensed under the MIT License — see the LICENSE file for details.
Parsi DateTime Picker
یک پکیج کامل برای انتخاب تاریخ و زمان فارسی (جلالی/شمسی) در Flutter با پشتیبانی از طراحی Material و Cupertino. این پکیج بر اساس imperial_persian_date ساخته شده و تبدیل دقیق تقویم را ارائه میدهد.
✨ ویژگی ویژه: تمام تاریخها در رابط کاربری به صورت تقویم شاهنشاهی (Imperial Persian) نمایش داده میشوند.
✨ ویژگیها
- 📅 انتخابگر تاریخ Material — تقویم جلالی زیبا با امکان حرکت بین ماهها و سالها
- 📆 انتخابگر بازه تاریخ — انتخاب تاریخ شروع و پایان با نمایش بصری بازه
- ⏰ انتخابگر زمان — انتخابگر زمان با پشتیبانی RTL و برچسبهای فارسی
- 🍎 انتخابگر Cupertino — انتخابگر به سبک iOS (تاریخ، زمان یا ترکیبی)
- ⌨️ حالت ورودی متنی — ورود مستقیم تاریخ به فرمت
YYYY/MM/DD - 🎨 پشتیبانی از Material 3 — طراحی مدرن با رنگبندی پویا
- 🔢 اعداد فارسی — تمام اعداد به صورت فارسی (۱۲۳۴۵۶۷۸۹۰)
- 👑 تقویم شاهنشاهی — نمایش سالها به صورت شاهنشاهی در تمام رابطهای کاربری
- 🎯 نمایش تعطیلات — مشخص کردن روزهای تعطیل با رنگ قرمز
- 🚫 غیرفعال کردن روزهای خاص — امکان غیرفعال کردن روزها یا روزهای هفته خاص
- 🌍 پشتیبانی چند زبانه — فارسی، دری، کردی، پشتو و انگلیسی
- 🎭 پشتیبانی کامل RTL — چیدمان کامل راست به چپ
- 🔄 تبدیل دوطرفه — تبدیل یکپارچه بین تقویمهای میلادی، شمسی و شاهنشاهی
📦 نصب
این خطوط را به فایل pubspec.yaml پروژه خود اضافه کنید:
dependencies:
parsi_datetime_picker: ^0.0.1
flutter_localizations:
sdk: flutter
سپس دستور زیر را اجرا کنید:
flutter pub get
🚀 شروع سریع
۱. تنظیم محلیسازی
import 'package:flutter/material.dart';
import 'package:parsi_datetime_picker/parsi_datetime_picker.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'نمونه Parsi Date Picker',
localizationsDelegates: parsiLocalizationsDelegates,
supportedLocales: parsiSupportedLocales,
locale: const Locale('fa', 'IR'),
home: const HomePage(),
);
}
}
۲. استفاده از انتخابگر تاریخ
final ParsiDate? picked = await showParsiDatePicker(
context: context,
initialDate: ParsiDate.now(),
firstDate: ParsiDate(2560, 1, 1),
lastDate: ParsiDate(2630, 12, 29),
helpText: 'انتخاب تاریخ',
);
if (picked != null) {
print('سال شاهنشاهی: ${picked.imperialYear}');
print('سال شمسی داخلی: ${picked.year}');
}
📖 نمونههای استفاده
انتخابگر تاریخ Material
final ParsiDate? date = await showParsiDatePicker(
context: context,
initialDate: ParsiDate.now(),
firstDate: ParsiDate(2560, 1, 1),
lastDate: ParsiDate(2630, 12, 29),
holidayDates: [
ParsiDate(2584, 1, 1),
ParsiDate(2584, 1, 2),
ParsiDate(2584, 1, 3),
],
selectableDayPredicate: (date) => date.weekDay != 7,
helpText: 'انتخاب تاریخ تولد',
cancelText: 'انصراف',
confirmText: 'تایید',
);
انتخابگر بازه تاریخ
final ParsiDateRange? range = await showParsiDateRangePicker(
context: context,
firstDate: ParsiDate(2560, 1, 1),
lastDate: ParsiDate(2630, 12, 29),
initialDateRange: ParsiDateRange(
start: ParsiDate(2584, 6, 1),
end: ParsiDate(2584, 6, 10),
),
helpText: 'انتخاب بازه تاریخ',
);
انتخابگر زمان
final TimeOfDay? time = await showParsiTimePicker(
context: context,
initialTime: TimeOfDay.now(),
helpText: 'انتخاب ساعت',
);
انتخابگر Cupertino
SizedBox(
height: 200,
child: ParsiCupertinoDatePicker(
mode: ParsiCupertinoDatePickerMode.date,
initialDateTime: ParsiDate.now(),
minimumDate: ParsiDate(2560, 1, 1),
maximumDate: ParsiDate(2630, 12, 29),
onDateTimeChanged: (date) {
setState(() => _selectedDate = date);
},
),
)
🗓️ API کلاس ParsiDate
سازندهها
ParsiDate(2584, 6, 15)
ParsiDate.now()
ParsiDate.fromDateTime(DateTime(2025, 9, 6))
ویژگیها
date.year // ۲۵۸۴
date.month // ۶
date.day // ۱۵
date.monthName // 'شهریور'
date.monthNameEn // 'Shahrivar'
date.weekDayName // 'سهشنبه'
date.weekDay // ۱-۷
date.isLeapYear // true/false
date.monthLength // ۲۹-۳۱
date.imperialYear // ۲۵۸۴
محاسبات تاریخ
date.addDays(5)
date.addMonths(2)
date.addYears(1)
date.copyWith(year: 2585, month: 7, day: 20)
مقایسه تاریخها
date1.isBefore(date2)
date1.isAfter(date2)
date1.isSameDay(date2)
date1.difference(date2)
date1.compareTo(date2)
قالببندی
date.format('WWWW، DD MMMM YYYY') // سهشنبه، ۱۵ شهریور ۲۵۸۴
date.format('YYYY/MM/DD HH:mm') // ۲۵۸۴/۰۶/۱۵ ۱۴:۳۰
توکنهای قالببندی
| توکن | توضیحات | مثال |
|---|---|---|
YYYY |
سال ۴ رقمی (شاهنشاهی) | ۲۵۸۴ |
MMMM |
نام کامل ماه (فارسی) | شهریور |
MMM |
نام ماه (انگلیسی) | Shahrivar |
MM |
ماه با صفر | ۰۶ |
DD |
روز با صفر | ۱۵ |
WWWW |
نام روز هفته | سهشنبه |
HH |
ساعت | ۱۴ |
mm |
دقیقه | ۳۰ |
ss |
ثانیه | ۰۵ |
🌍 سیستمهای تقویمی
۱. شمسی (هجری شمسی)
تقویم رسمی ایران — برای محاسبات داخلی استفاده میشود.
۲. میلادی (Gregorian)
تقویم استاندارد بینالمللی.
۳. شاهنشاهی (Imperial Persian) ⭐
- سال ۱ = ۵۵۹ قبل از میلاد (تاجگذاری کوروش بزرگ)
- تبدیل: سال شاهنشاهی = سال شمسی + ۱۱۸۰
- در تمام رابطهای کاربری نمایش داده میشود
جدول تبدیل سریع
| سال شمسی | سال شاهنشاهی | سال میلادی |
|---|---|---|
| ۱۳۰۰ | ۲۴۸۰ | ۱۹۲۱ |
| ۱۳۵۷ | ۲۵۳۷ | ۱۹۷۸ |
| ۱۴۰۰ | ۲۵۸۰ | ۲۰۲۱ |
| ۱۴۰۴ | ۲۵۸۴ | ۲۰۲۵ |
| ۱۴۵۰ | ۲۶۳۰ | ۲۰۷۱ |
📱 پشتیبانی از پلتفرمها
✅ Android ✅ iOS ✅ Web ✅ macOS ✅ Windows ✅ Linux
🤝 مشارکت
مشارکتها خوشآمدید! لطفاً Pull Request ارسال کنید.
📄 مجوز
این پروژه تحت مجوز MIT منتشر شده — فایل LICENSE را ببینید.