Skip to content

harshyadavDeveloper/smart_date_formatter

Repository files navigation

smart_date_formatter

Pub Version Pub Likes Pub Points Popularity MIT License CI

Live Playground

The complete Flutter DateTime toolkit.
Format • Parse • Calculate • Localize • Widget-Ready • Analytics

👉 Try the Interactive Playground — no installation needed!


✨ Features

Feature Description
⏱️ Relative time "Just now", "2 hours ago", "Last week"
📅 Calendar strings "Today", "Yesterday", "Monday", "12 Jan 2024"
🕐 Short timestamps "2:30 PM", "Mon 4:15 PM", "5 Mar"
🎨 Custom formats format('dd-MM-yyyy'), toReadable, to12Hour
🧮 Date calculations addWorkingDays, daysUntil, isBetween, age
📆 Range helpers startOfWeek, endOfMonth, quarter, weekOfYear
🌍 16 Languages English, Hindi, Marathi, Gujarati, Bengali, Tamil, Telugu, Kannada, Punjabi, Spanish, French, German, Russian, Chinese, Japanese, Arabic
🔍 Smart parsing "tomorrow" → DateTime, "next monday" → DateTime
⏱️ TimeAgoText Auto-refreshing Flutter widget
CountdownText Live countdown Flutter widget
🏷️ DateBadge Smart date chip widget
📝 SmartDateText All-in-one date text widget
🔧 RelativeDateBuilder Builder pattern for custom UI
🗄️ DateRangeHelper Ready-made ranges for DB queries
🎄 HolidayHelper Holiday detection + working days
🔁 RecurrenceHelper Generate recurring date lists
📊 StreakCalculator Habit/attendance streak analysis
📈 DateGrouper Group dates by day/week/month/year
Boolean helpers isToday, isWeekend, isMorning, isPast
🪶 Zero dependencies Pure Flutter — no external packages
💙 Null safe Full Dart null safety

📦 Installation

dependencies:
  smart_date_formatter: ^1.5.0
flutter pub get

🚀 Quick Start

import 'package:smart_date_formatter/smart_date_formatter.dart';

// ⏱️ Relative time
DateTime.now().subtract(Duration(hours: 2)).timeAgo;    // "2 hours ago"
DateTime.now().add(Duration(days: 1)).timeAgo;           // "Tomorrow"

// 📅 Calendar
DateTime.now().calendar;                                  // "Today"

// 🎨 Custom format
DateTime.now().format('dd-MM-yyyy');                      // "15-06-2024"
DateTime.now().toReadable;                                // "Saturday, 15 June 2024"

// 🌍 Localization
date.timeAgoIn(SdfLocale.hi);                             // "2 घंटे पहले"
date.timeAgoIn(SdfLocale.mr);                             // "2 तास पूर्वी"

// 🔍 Smart parsing
SmartParser.parse("next monday");                         // DateTime
SmartParser.parse("in 3 days");                           // DateTime

// ⏱️ Auto-refreshing widget
TimeAgoText(date: message.sentAt)

// ⏳ Countdown widget
CountdownText(target: event.startsAt, format: '{d}d {h}h {m}m {s}s')

// 🏷️ Date badge
DateBadge(date: DateTime.now())                           // "TODAY" chip

// 🗄️ Date ranges
DateRangeHelper.thisMonth()                               // DateRange(start, end)
DateRangeHelper.lastNDays(30)

// 🎄 Holiday support
date.isHoliday(holidays: HolidayHelper.indianHolidays(2024))
date.addWorkingDaysWithHolidays(5, holidays: holidays)

// 🔁 Recurrence
RecurrenceHelper.weekly(start: date, count: 8)

// 📊 Streak & Analytics
StreakCalculator.currentStreak(habitDates)               // 7
StreakCalculator.longestStreak(habitDates)               // 21
DateGrouper.byMonth(activityDates)                       // {'2024-06': [...]}
DateGrouper.mostActiveWeekday(activityDates)             // 'Monday'

📖 Complete API Reference

1️⃣ Relative Time

date.timeAgo                    // "2 hours ago"
date.timeAgoIn(SdfLocale.hi)   // "2 घंटे पहले"
date.calendar                   // "Today", "Yesterday", "Monday"
date.shortTimestamp             // "2:30 PM", "Mon 4:15 PM"

2️⃣ Custom Format

date.format('dd-MM-yyyy')          // "15-06-2024"
date.format('MMM dd, yyyy')        // "Jun 15, 2024"
date.format('EEEE, dd MMMM yyyy')  // "Saturday, 15 June 2024"
date.format('hh:mm a')             // "02:30 PM"
date.format('HH:mm:ss')            // "14:30:45"
date.toReadable                    // "Saturday, 15 June 2024"
date.toISO                         // "2024-06-15T14:30:45"
date.to12Hour                      // "02:30 PM"
date.to24Hour                      // "14:30"
date.toTimeString                  // "14:30:45"

Format tokens:

Token Output Token Output
dd 15 EEEE Saturday
d 5 EEE Sat
MM 06 yyyy 2024
MMM Jun yy 24
MMMM June HH 14
hh 02 mm 30
ss 45 a PM

3️⃣ Boolean Extensions

date.isToday       date.isYesterday    date.isTomorrow
date.isPast        date.isFuture
date.isWeekend     date.isWeekday
date.isMorning     date.isAfternoon
date.isEvening     date.isNight
date.isSameDay(other)    date.isSameWeek(other)
date.isSameMonth(other)  date.isSameYear(other)
date.isBetween(start, end)

4️⃣ Date Calculations

// Working days
date.addWorkingDays(5)
date.workingDaysUntil(other)

// Days between
date.daysUntil(other)
date.daysSince(other)

// Age
DateTime(1999, 5, 20).age           // 25

// Quarter & Year
date.quarter                         // 2
date.isQ1 / isQ2 / isQ3 / isQ4
date.weekOfYear                      // 24
date.dayOfYear                       // 167
date.isLeapYear                      // true

// Next/Previous weekday
date.nextMonday     date.nextFriday
date.previousMonday date.previousFriday
// ... all 7 weekdays supported

// Boundaries
date.startOfDay    date.endOfDay
date.startOfWeek   date.endOfWeek
date.startOfMonth  date.endOfMonth
date.startOfYear   date.endOfYear

// Copy with
date.copyWith(hour: 0, minute: 0)

5️⃣ Localization 🌍

// 16 supported languages
SmartDateFormatter(locale: SdfLocale.hi).format(date)
date.timeAgoIn(SdfLocale.mr)    // "2 तास पूर्वी"
date.timeAgoIn(SdfLocale.bn)    // "2 ঘন্টা আগে"
SdfLocale.fromCode('ta')        // Tamil
Code Language Code Language
en English 🇬🇧 de German 🇩🇪
hi Hindi 🇮🇳 ru Russian 🇷🇺
mr Marathi 🇮🇳 zh Chinese 🇨🇳
gu Gujarati 🇮🇳 ja Japanese 🇯🇵
bn Bengali 🇮🇳 ar Arabic 🇸🇦
ta Tamil 🇮🇳 es Spanish 🇪🇸
te Telugu 🇮🇳 fr French 🇫🇷
kn Kannada 🇮🇳 pa Punjabi 🇮🇳

6️⃣ Smart Parser 🔍

SmartParser.parse("today")         // DateTime
SmartParser.parse("tomorrow")      // DateTime
SmartParser.parse("in 3 days")     // DateTime
SmartParser.parse("next monday")   // DateTime
SmartParser.parse("2 weeks ago")   // DateTime
SmartParser.parse("last year")     // DateTime
SmartParser.parse("2024-06-15")    // DateTime
SmartParser.canParse("tomorrow")   // true
SmartParser.parseOrThrow("blah")   // FormatException

7️⃣ Widgets

TimeAgoText ⏱️

TimeAgoText(
  date: message.sentAt,
  locale: SdfLocale.hi,
  refreshRate: Duration(seconds: 30),
  prefix: 'Posted ',
  style: TextStyle(color: Colors.grey),
)

CountdownText ⏳

CountdownText(
  target: saleEndsAt,
  format: '{hh}:{mm}:{ss}',
  finishedText: 'Sale Ended!',
  onFinished: () => hideSaleBanner(),
  style: TextStyle(color: Colors.red, fontSize: 24),
)

DateBadge 🏷️

DateBadge(date: DateTime.now())
DateBadge(date: date, style: DateBadgeStyle.outlined)
DateBadge(date: date, style: DateBadgeStyle.flat)
DateBadge(date: date, label: 'NEW', uppercase: true)

SmartDateText 📝

SmartDateText(date: date, mode: SmartDateMode.auto)
SmartDateText(date: date, mode: SmartDateMode.timeAgo)
SmartDateText(date: date, mode: SmartDateMode.calendar)
SmartDateText(
  date: date,
  mode: SmartDateMode.custom,
  pattern: 'dd-MM-yyyy',
  autoRefresh: true,
)

RelativeDateBuilder 🔧

RelativeDateBuilder(
  date: post.createdAt,
  autoRefresh: true,
  builder: (ctx, timeAgo, calendar, timestamp, date) {
    return Row(children: [
      Icon(Icons.access_time, size: 12),
      Text(timeAgo),
      if (date.isToday) Badge(label: Text('NEW')),
    ]);
  },
)

🗓️ SmartCalendar Widget

Full featured calendar with month, week, day, and agenda views.

SmartCalendar(
  events: [
    // Single day event
    CalendarEvent(
      date: DateTime(2024, 6, 15),
      title: 'Team Meeting',
      color: Colors.blue,
      allDay: false,
      startTime: TimeOfDay(hour: 10, minute: 0),
    ),

    // Multi-day event 🆕
    CalendarEvent(
      date: DateTime(2024, 6, 15),
      endDate: DateTime(2024, 6, 17),
      title: 'Company Retreat',
      color: Colors.teal,
    ),
  ],
  initialView: CalendarView.month,  // month, week, day, agenda
  markerStyle: EventMarkerStyle.dot, // dot, chip, both
  selectedColor: Colors.indigo,
  showViewSwitcher: true,
  showTodayButton: true,
  agendaDaysAhead: 30,
  onDateSelected: (date, events) => print(date),
  onEventTap: (event) => print(event.title),
  // 👈 Swipe left/right to navigate!
)

CalendarEvent properties:

event.isMultiDay        // true for multi-day events
event.spanDays          // number of days (3)
event.dateRangeString   // "15/6/2024 – 17/6/2024"
event.isOnDate(date)    // true if date is in event range
event.startsOnDate(date)
event.endsOnDate(date)
event.timeString        // "10:00 AM – 11:00 AM"

SmartCalendarController:

final controller = SmartCalendarController();
controller.nextMonth();
controller.previousWeek();
controller.jumpToDate(DateTime(2024, 12, 25));
controller.goToToday();
controller.selectDate(date);
Property Type Default Description
events List<CalendarEvent> [] Events to display
initialView CalendarView month Initial view mode
markerStyle EventMarkerStyle dot Event marker style
selectedColor Color indigo Selected date color
todayColor Color blue Today highlight color
showViewSwitcher bool true Show view tabs
showTodayButton bool true Show Today button
agendaDaysAhead int 30 Days ahead in agenda
agendaDaysBehind int 7 Days behind in agenda
firstDayOfWeek int 1 1=Monday, 7=Sunday

8️⃣ DateRangeHelper 🗄️

DateRangeHelper.today()           DateRangeHelper.yesterday()
DateRangeHelper.thisWeek()        DateRangeHelper.lastWeek()
DateRangeHelper.thisMonth()       DateRangeHelper.lastMonth()
DateRangeHelper.thisYear()        DateRangeHelper.lastYear()
DateRangeHelper.lastNDays(30)     DateRangeHelper.nextNDays(14)
DateRangeHelper.quarter(2)        DateRangeHelper.currentQuarter()
DateRangeHelper.custom(start, end)

// Use with DB
final range = DateRangeHelper.thisMonth();
await db.query(
  where: 'created_at BETWEEN ? AND ?',
  whereArgs: [range.start.toIso8601String(), range.end.toIso8601String()],
);
range.contains(DateTime.now());  // true
range.days;                       // 30
range.overlaps(otherRange);       // true/false

9️⃣ HolidayHelper 🎄

// Check
date.isHoliday(holidays: holidays)
date.isWorkingDay(holidays: holidays)

// Add working days skipping holidays
date.addWorkingDaysWithHolidays(5, holidays: holidays)
date.workingDaysUntilWithHolidays(deadline, holidays: holidays)

// Static methods
HolidayHelper.isHoliday(date, holidays: list)
HolidayHelper.nextWorkingDay(date, holidays: list)
HolidayHelper.workingDaysBetween(start, end, holidays: list)

// Preset lists
HolidayHelper.indianHolidays(2024)   // 8 Indian holidays
HolidayHelper.globalHolidays(2024)   // New Year, Christmas, Boxing Day

🔟 RecurrenceHelper 🔁

RecurrenceHelper.daily(start: date, count: 30)
RecurrenceHelper.weekly(start: date, count: 8)
RecurrenceHelper.monthly(start: date, count: 12)
RecurrenceHelper.yearly(start: date, count: 5)

// With options
RecurrenceHelper.daily(
  start: date,
  count: 10,
  skipWeekends: true,
  skipHolidays: HolidayHelper.indianHolidays(2024),
)

// Until date
RecurrenceHelper.monthly(
  start: date,
  until: DateTime(2024, 12, 31),
)

// Next occurrence
RecurrenceHelper.nextOccurrence(date, RecurrenceFrequency.weekly)

1️⃣1️⃣ StreakCalculator 📊

StreakCalculator.currentStreak(dates)    // 7
StreakCalculator.longestStreak(dates)    // 21
StreakCalculator.isTodayCompleted(dates) // true
StreakCalculator.totalCompleted(dates)   // 45
StreakCalculator.allStreaks(dates)        // [[...], [...]]
StreakCalculator.lastCompletedDate(dates) // DateTime
StreakCalculator.missedDays(dates, start: startDate)
StreakCalculator.completionRate(
  dates,
  start: DateTime(2024, 6, 1),
  end: DateTime(2024, 6, 30),
) // 0.8

1️⃣2️⃣ DateGrouper 📈

DateGrouper.byDay(dates)      // {'2024-06-15': [...]}
DateGrouper.byWeek(dates)     // {'2024-W24': [...]}
DateGrouper.byMonth(dates)    // {'2024-06': [...]}
DateGrouper.byQuarter(dates)  // {'2024-Q2': [...]}
DateGrouper.byYear(dates)     // {'2024': [...]}
DateGrouper.byHour(dates)     // {'14': [...]}
DateGrouper.byWeekday(dates)  // {'Monday': [...]}

// Counts
DateGrouper.countByDay(dates)
DateGrouper.countByMonth(dates)
DateGrouper.countByWeekday(dates)

// Insights
DateGrouper.mostActiveDay(dates)      // '2024-06-15'
DateGrouper.mostActiveWeekday(dates)  // 'Monday'
DateGrouper.mostActiveHour(dates)     // 14
DateGrouper.averageGap(dates)         // Duration(days: 2)

💡 Real World Examples

Chat App

// Auto-refreshing message timestamp
TimeAgoText(
  date: message.sentAt,
  style: TextStyle(fontSize: 10, color: Colors.grey),
  refreshRate: Duration(seconds: 30),
)

Habit Tracker

// Daily streak
final streak = StreakCalculator.currentStreak(completedDates);
final rate = StreakCalculator.completionRate(
  completedDates,
  start: monthStart,
  end: monthEnd,
);
Text('🔥 $streak day streak  •  ${(rate*100).toInt()}% this month')

Analytics Dashboard

// Group user activity
final byWeekday = DateGrouper.countByWeekday(loginDates);
final mostActive = DateGrouper.mostActiveWeekday(loginDates);
// Show bar chart of activity by day

HR System

// Working days between dates skipping holidays
final leaveDays = HolidayHelper.workingDaysBetween(
  leaveStart, leaveEnd,
  holidays: HolidayHelper.indianHolidays(DateTime.now().year),
);

Subscription App

// Generate billing dates
final billingDates = RecurrenceHelper.monthly(
  start: subscriptionStart,
  until: subscriptionEnd,
);

Invoice System

// Company date format
Text('Invoice Date: ${date.format('dd-MM-yyyy')}')
Text('Due Date: ${dueDate.format('dd MMM yyyy')}')

Multilingual App

final locale = SdfLocale.fromCode(
  Localizations.localeOf(context).languageCode,
);
Text(post.createdAt.timeAgoIn(locale))

🔄 Before vs After

// ❌ Before — 3 packages + 120 lines every project
dependencies:
  timeago: ^3.6.0
  intl: ^0.18.0

// ✅ After — one package, complete toolkit
dependencies:
  smart_date_formatter: ^1.5.0

date.timeAgo                    // relative time
date.format('dd-MM-yyyy')       // custom format
date.timeAgoIn(SdfLocale.hi)   // localization
SmartParser.parse("tomorrow")   // natural language
TimeAgoText(date: date)         // auto-refresh widget
DateRangeHelper.thisMonth()     // DB query range
StreakCalculator.currentStreak(dates) // analytics

🧪 Testing

flutter test

200+ tests covering all features and edge cases.


🤝 Contributing

  1. Fork — github.com/harshyadavDeveloper/smart_date_formatter
  2. Create branch — git checkout -b feat/your-feature
  3. Commit — git commit -m 'feat: add your feature'
  4. Push — git push origin feat/your-feature
  5. Open a Pull Request

🐛 Issues & Feedback

👉 Open an issue


📄 License

MIT License — see LICENSE for details.


👨‍💻 Author

Made with 💙 by Harsh Yadav

If this package helped you — please ⭐ the repo and 👍 like it on pub.dev!

pub.dev GitHub

About

A lightweight Flutter/Dart package for smart, readable, and flexible date formatting with localization and relative time support.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors