📅 DateTime Helpers for Flutter

A powerful, modular, zero-dependency date/time library for Flutter

Dart Flutter

Pure DartZero Dependencies7 Languages100+ FunctionsFully Modular

FeaturesInstallationQuick StartDocumentationExamples


Demo Video


✨ Highlights

// 🌍 Multi-language support out of the box
DateFormatters.formatDateLong(DateTime.now());              // "December 1, 2025"
DateFormatters.formatDateLong(DateTime.now(), 'es_ES');     // "1 de Diciembre de 2025"
DateFormatters.formatDateLong(DateTime.now(), 'ar_SA');     // "1 ديسمبر 2025"

// ⏰ Smart relative time
RelativeTime.getRelativeTime(twoHoursAgo);                  // "2 hours ago"
RelativeTime.getRelativeTime(tomorrow, 'fr_FR');            // "dans 1 jour"

// 🧠 Context-aware formatting
SmartFormatters.formatSmart(DateTime.now());                // "Today at 2:30 PM"
SmartFormatters.formatSmart(yesterday);                     // "Yesterday at 2:30 PM"

// 🔢 Advanced calculations
DateCalculations.addBusinessDays(DateTime.now(), 5);        // Skips weekends
DateCalculations.calculateAge(birthDate);                   // Age in years

🎯 Why Choose This Library?

Feature This Library Others
📦 Dependencies ✅ Zero ❌ External packages
🌍 Languages ✅ 7 built-in ⚠️ Requires setup
🧩 Modular ✅ Import what you need ❌ Monolithic
Performance ✅ Lightweight (<50KB) ⚠️ Heavy packages
🎨 Customizable ✅ Pure Dart, modify easily ⚠️ Limited
📱 Platforms ✅ All (Web, Mobile, Desktop) ⚠️ Platform-specific
🔧 Maintenance ✅ No version conflicts ⚠️ Breaking changes

🚀 Features

📅 Date Formatting

  • 14+ format functions - Short, medium, long, full, custom
  • Multi-language - 7 languages with proper localization
  • Custom patterns - yyyy-MM-dd, ISO 8601, and more
  • Date ranges - Smart range formatting
  • Ordinal dates - "1st", "2nd", "3rd" in English

⏰ Time Formatting

  • 12/24-hour formats - With or without seconds
  • Combined date/time - Multiple combined formats
  • Milliseconds support - For precise timing
  • Flexible display - AM/PM, military time, etc.

🔍 Date Comparisons

  • 45+ comparison methods - Comprehensive date/time checks
  • Smart checks - isToday, isYesterday, isTomorrow
  • Period checks - isThisWeek, isThisMonth, isThisYear, isLastWeek, isNextWeek
  • Weekday checks - isMonday through isSunday, isWeekend, isWeekday
  • Time of day - isMorning, isAfternoon, isEvening, isNight
  • Range checks - isBetween, isWithinDays, isWithinWeeks, isWithinMonths
  • Relative checks - isPast, isFuture
  • Precision checks - isSameHour, isSameMinute
  • Period checks - isFirstHalfOfMonth, isSecondHalfOfMonth, quarter checks
  • Leap year - isLeapYear, isLeapYearDate

🧮 Date Calculations

  • 45+ calculation methods - Comprehensive date/time arithmetic
  • Period boundaries - Start/end of day, week, month, year, quarter, hour, minute
  • Business days - Add, subtract, count (skips weekends)
  • Age calculation - From birthdate with proper handling
  • Date arithmetic - Add/subtract years, months, weeks, days
  • Month arithmetic - Handles edge cases (Jan 31 + 1 month = Feb 28)
  • Date differences - Days/weeks/months/years between dates, daysUntil, daysSince
  • Rounding utilities - roundToHour, roundToDay
  • Weekday utilities - getNthWeekdayOfMonth, getLastWeekdayOfMonth, getNextWeekday
  • Leap year support - Accurate calculations
  • Week numbers - ISO week number calculation
  • Timezone utilities - UTC conversion, offset formatting
  • Utility functions - clamp, min, max for date comparisons

⏱️ Relative Time

  • Past/Future - "2 hours ago", "in 3 days"
  • Multi-language - Relative time in 5 languages
  • Short format - "2h", "3d" for compact UI
  • Duration formatting - Pretty duration strings
  • Countdown - Time remaining to target date
  • Verbose mode - "2 hours, 30 minutes" format

🎨 Smart Features

  • Context-aware formatting - Adapts to date proximity
  • Flexible parsing - Parse multiple date formats
  • Date validation - Check if string is valid date
  • File-safe formatting - For filenames (no special chars)
  • Custom patterns - Extend easily for your needs

🌍 Supported Languages

  • 🇬🇧 English (en, en_US, en_GB)
  • 🇪🇸 Spanish (es, es_ES)
  • 🇫🇷 French (fr, fr_FR)
  • 🇩🇪 German (de, de_DE)
  • 🇸🇦 Arabic (ar, ar_SA) - RTL support
  • 🇯🇵 Japanese (ja, ja_JP)
  • 🇨🇳 Chinese (zh, zh_CN)

📦 Installation

Add this to your package's pubspec.yaml file:

dependencies:
  save_points_intl: ^1.1.0

Then install it:

flutter pub get

Import

import 'package:save_points_intl/save_points_intl.dart';

// Or import specific modules
import 'package:save_points_intl/save_points_intl_date_formatters.dart';
import 'package:save_points_intl/save_points_intl_time_formatters.dart';

No external dependencies required! This package is 100% pure Dart with zero dependencies.

Package Structure

The package follows a modular architecture - import only what you need:

// Import everything (recommended for most use cases)
import 'package:save_points_intl/save_points_intl.dart';

// Or import specific modules to reduce bundle size
import 'package:save_points_intl/save_points_intl_date_formatters.dart';
import 'package:save_points_intl/save_points_intl_time_formatters.dart';
import 'package:save_points_intl/save_points_intl_date_comparisons.dart';
import 'package:save_points_intl/save_points_intl_date_calculations.dart';
import 'package:save_points_intl/save_points_intl_relative_time.dart';
import 'package:save_points_intl/save_points_intl_smart_formatters.dart';
import 'package:save_points_intl/save_points_intl_date_parsers.dart';

⚡ Quick Start

1. Import the Library

// Import everything (recommended)
import 'package:save_points_intl/save_points_intl.dart';

// Or import specific modules
import 'package:save_points_intl/save_points_intl_date_formatters.dart';
import 'package:save_points_intl/save_points_intl_time_formatters.dart';

2. Use It!

final now = DateTime.now();

// Date formatting
print(DateFormatters.formatDateLong(now));       // "December 1, 2025"

// Time formatting
print(TimeFormatters.formatTime12Hour(now));     // "2:30 PM"

// Relative time
final twoHoursAgo = now.subtract(Duration(hours: 2));
print(RelativeTime.getRelativeTime(twoHoursAgo)); // "2 hours ago"

// Date comparisons
if (DateComparisons.isToday(now)) {
  print('It\'s today!');
}

// Date calculations
final nextWeek = DateCalculations.addBusinessDays(now, 5);
print(DateFormatters.formatDateMedium(nextWeek)); // Next business week

📚 Documentation

📖 Complete Guides

📋 Quick Reference

Date Formatting Functions (14+)
DateFormatters.formatDateShort(date);         // "12/1/2025"
DateFormatters.formatDateMedium(date);        // "Dec 1, 2025"
DateFormatters.formatDateLong(date);          // "December 1, 2025"
DateFormatters.formatDateFull(date);          // "Monday, December 1, 2025"
DateFormatters.formatYear(date);              // "2025"
DateFormatters.formatMonthYear(date);         // "December 2025"
DateFormatters.formatDayMonth(date);          // "December 1"
DateFormatters.formatDayName(date);           // "Monday"
DateFormatters.formatMonthName(date);         // "December"
DateFormatters.formatCustom(date, 'yyyy-MM-dd'); // "2025-12-01"
DateFormatters.formatIso8601(date);           // ISO 8601 format
DateFormatters.formatForFileName(date);       // File-safe format
DateFormatters.formatDateRange(start, end);   // Date range
Time Formatting Functions (8+)
TimeFormatters.formatTime12Hour(date);              // "2:30 PM"
TimeFormatters.formatTime24Hour(date);              // "14:30"
TimeFormatters.formatTime12HourWithSeconds(date);   // "2:30:45 PM"
TimeFormatters.formatTime24HourWithSeconds(date);   // "14:30:45"
TimeFormatters.formatTimeWithMilliseconds(date);    // "14:30:45.123"
TimeFormatters.formatDateTimeShort(date);           // "12/1/2025 2:30 PM"
TimeFormatters.formatDateTimeMedium(date);          // "Dec 1, 2025 2:30 PM"
TimeFormatters.formatDateTimeLong(date);            // "December 1, 2025 at 2:30 PM"
Date Comparison Functions (13+)
DateComparisons.isSameDay(date1, date2);      // Same day?
DateComparisons.isSameWeek(date1, date2);     // Same week?
DateComparisons.isSameMonth(date1, date2);    // Same month?
DateComparisons.isSameYear(date1, date2);     // Same year?
DateComparisons.isToday(date);                // Is today?
DateComparisons.isYesterday(date);            // Is yesterday?
DateComparisons.isTomorrow(date);             // Is tomorrow?
DateComparisons.isThisWeek(date);             // In current week?
DateComparisons.isThisMonth(date);            // In current month?
DateComparisons.isThisYear(date);             // In current year?
DateComparisons.isPast(date);                 // In the past?
DateComparisons.isFuture(date);               // In the future?
DateComparisons.isWeekend(date);              // Saturday/Sunday?
DateComparisons.isWeekday(date);              // Monday-Friday?
DateComparisons.isBetween(date, start, end);  // In date range?
Date Calculation Functions (20+)
// Period boundaries
DateCalculations.startOfDay(date);            // 00:00:00
DateCalculations.endOfDay(date);              // 23:59:59.999
DateCalculations.startOfWeek(date);           // Monday 00:00
DateCalculations.endOfWeek(date);             // Sunday 23:59
DateCalculations.startOfMonth(date);          // 1st day of month
DateCalculations.endOfMonth(date);            // Last day of month
DateCalculations.startOfYear(date);           // Jan 1st
DateCalculations.endOfYear(date);             // Dec 31st
DateCalculations.startOfQuarter(date);        // Quarter start
DateCalculations.endOfQuarter(date);          // Quarter end

// Business days
DateCalculations.addBusinessDays(date, 5);    // +5 weekdays
DateCalculations.subtractBusinessDays(date, 5); // -5 weekdays
DateCalculations.countBusinessDays(start, end); // Count weekdays

// Calculations
DateCalculations.calculateAge(birthDate);     // Age in years
DateCalculations.getDaysInMonth(year, month); // Days in month
DateCalculations.isLeapYear(year);            // Leap year?
DateCalculations.getQuarter(date);            // Quarter number (1-4)
DateCalculations.getWeekNumber(date);         // Week number in year
DateCalculations.addMonths(date, 3);          // +3 months (smart)
DateCalculations.subtractMonths(date, 3);     // -3 months
DateCalculations.getDifference(start, end);   // Detailed difference

// Timezone
DateCalculations.toUTC(date);                 // Convert to UTC
DateCalculations.toLocal(date);               // Convert to local
DateCalculations.formatTimezoneOffset(date);  // "+05:30"
DateCalculations.getTimezoneName(date);       // "PST"
Relative Time Functions (5+)
RelativeTime.getRelativeTime(date);           // "2 hours ago"
RelativeTime.getRelativeTime(date, 'es_ES');  // "hace 2 horas"
RelativeTime.getRelativeTimeShort(date);      // "2h"
RelativeTime.formatDuration(duration);        // "2h 30m"
RelativeTime.formatTimeRemaining(targetDate); // Countdown
Smart & Parsing Functions (4+)
// Smart formatting
SmartFormatters.formatSmart(date);            // Context-aware

// Parsing
DateParsers.parseDate(dateString);            // Parse date
DateParsers.parseFlexible(dateString);        // Try multiple formats
DateParsers.isValidDate(dateString);          // Validate date string

💡 Examples

🎯 Real-World Use Cases

Chat/Messaging App
import 'package:save_points_intl/datetime.dart';

String formatMessageTimestamp(DateTime messageTime) {
  if (DateComparisons.isToday(messageTime)) {
    return TimeFormatters.formatTime12Hour(messageTime); // "2:30 PM"
  } else if (DateComparisons.isYesterday(messageTime)) {
    return 'Yesterday';
  } else if (DateComparisons.isThisWeek(messageTime)) {
    return DateFormatters.formatDayName(messageTime); // "Monday"
  } else if (DateComparisons.isThisYear(messageTime)) {
    return DateFormatters.formatDayMonth(messageTime); // "Nov 30"
  } else {
    return DateFormatters.formatDateShort(messageTime); // "11/30/2024"
  }
}

// Usage
final timestamp = formatMessageTimestamp(messageDate);
print('Message sent: $timestamp');
Event Calendar
import 'package:save_points_intl/datetime.dart';

class Event {
  final String title;
  final DateTime startTime;
  
  Event(this.title, this.startTime);
  
  String getDisplayTime() {
    if (DateComparisons.isToday(startTime)) {
      return 'Today at ${TimeFormatters.formatTime12Hour(startTime)}';
    } else if (DateComparisons.isTomorrow(startTime)) {
      return 'Tomorrow at ${TimeFormatters.formatTime12Hour(startTime)}';
    } else if (DateComparisons.isThisWeek(startTime)) {
      return '${DateFormatters.formatDayName(startTime)} at ${TimeFormatters.formatTime12Hour(startTime)}';
    } else {
      return TimeFormatters.formatDateTimeMedium(startTime);
    }
  }
  
  String getCountdown() {
    return RelativeTime.getRelativeTime(startTime);
  }
}

// Usage
final meeting = Event('Team Meeting', DateTime.now().add(Duration(hours: 3)));
print(meeting.getDisplayTime());  // "Today at 5:30 PM"
print(meeting.getCountdown());    // "in 3 hours"
Social Media Feed
import 'package:save_points_intl/datetime.dart';

class Post {
  final String content;
  final DateTime publishedAt;
  
  Post(this.content, this.publishedAt);
  
  String getTimestamp() {
    final diff = DateTime.now().difference(publishedAt);
    
    if (diff.inMinutes < 1) return 'Just now';
    if (diff.inHours < 1) return '${diff.inMinutes}m';
    if (diff.inHours < 24) return '${diff.inHours}h';
    if (diff.inDays < 7) return '${diff.inDays}d';
    
    return DateFormatters.formatDateMedium(publishedAt);
  }
}

// Usage
final post = Post('Hello World!', DateTime.now().subtract(Duration(hours: 2)));
print(post.getTimestamp()); // "2h"
Booking System
import 'package:save_points_intl/datetime.dart';

class Reservation {
  final DateTime checkIn;
  final DateTime checkOut;
  
  Reservation(this.checkIn, this.checkOut);
  
  int get numberOfNights => checkOut.difference(checkIn).inDays;
  
  int get businessDays => 
      DateCalculations.countBusinessDays(checkIn, checkOut);
  
  String getStayPeriod() => 
      DateFormatters.formatDateRange(checkIn, checkOut);
  
  String getStatus() {
    if (DateComparisons.isToday(checkIn)) {
      return 'Checking in today';
    } else if (DateComparisons.isPast(checkIn) && 
               DateComparisons.isFuture(checkOut)) {
      return 'Currently staying';
    } else if (DateComparisons.isPast(checkOut)) {
      return 'Checked out';
    } else {
      return 'Checking in ${RelativeTime.getRelativeTime(checkIn)}';
    }
  }
}

// Usage
final reservation = Reservation(
  DateTime.now().add(Duration(days: 3)),
  DateTime.now().add(Duration(days: 8)),
);
print('Period: ${reservation.getStayPeriod()}');
print('Nights: ${reservation.numberOfNights}');
print('Status: ${reservation.getStatus()}');
Task Manager
import 'package:save_points_intl/datetime.dart';

class Task {
  final String name;
  final DateTime dueDate;
  DateTime? completedDate;
  
  Task(this.name, this.dueDate);
  
  bool get isOverdue => 
      completedDate == null && DateComparisons.isPast(dueDate);
  
  bool get isDueToday => 
      completedDate == null && DateComparisons.isToday(dueDate);
  
  String getStatus() {
    if (completedDate != null) {
      return 'Completed ${RelativeTime.getRelativeTime(completedDate!)}';
    }
    
    if (isOverdue) {
      final days = DateTime.now().difference(dueDate).inDays;
      return '⚠️ Overdue by $days day${days == 1 ? '' : 's'}';
    }
    
    if (isDueToday) {
      return '📅 Due today at ${TimeFormatters.formatTime12Hour(dueDate)}';
    }
    
    return '⏰ Due ${RelativeTime.getRelativeTime(dueDate)}';
  }
}

// Usage
final task = Task('Submit report', DateTime.now().add(Duration(hours: 5)));
print(task.getStatus()); // "⏰ Due in 5 hours"
Multi-Language App
import 'package:save_points_intl/datetime.dart';

class LocalizedDateService {
  final String locale;
  
  LocalizedDateService(this.locale);
  
  String formatDate(DateTime date) {
    return DateFormatters.formatDateLong(date, locale);
  }
  
  String formatTime(DateTime date) {
    return TimeFormatters.formatTime12Hour(date, locale);
  }
  
  String formatRelative(DateTime date) {
    return RelativeTime.getRelativeTime(date, locale);
  }
}

// Usage
final english = LocalizedDateService('en_US');
final spanish = LocalizedDateService('es_ES');
final arabic = LocalizedDateService('ar_SA');

final now = DateTime.now();
print(english.formatDate(now));  // "December 1, 2025"
print(spanish.formatDate(now));  // "1 de Diciembre de 2025"
print(arabic.formatDate(now));   // "1 ديسمبر 2025"

🎨 Advanced Usage

Custom Date Patterns

// ISO 8601
DateFormatters.formatCustom(date, 'yyyy-MM-dd');        // "2025-12-01"

// European format
DateFormatters.formatCustom(date, 'dd/MM/yyyy');        // "01/12/2025"

// American with time
DateFormatters.formatCustom(date, 'MM/dd/yyyy HH:mm');  // "12/01/2025 14:30"

// Custom format
DateFormatters.formatCustom(date, 'yyyy-MM-dd_HH-mm-ss'); // "2025-12-01_14-30-45"

Business Logic

// Get next business day
final tomorrow = DateTime.now().add(Duration(days: 1));
final nextBusinessDay = DateComparisons.isWeekend(tomorrow)
    ? DateCalculations.addBusinessDays(DateTime.now(), 1)
    : tomorrow;

// Count working days in month
final startOfMonth = DateCalculations.startOfMonth(DateTime.now());
final endOfMonth = DateCalculations.endOfMonth(DateTime.now());
final workingDays = DateCalculations.countBusinessDays(startOfMonth, endOfMonth);
print('Working days this month: $workingDays');

// Calculate deadline (5 business days from now)
final deadline = DateCalculations.addBusinessDays(DateTime.now(), 5);
print('Deadline: ${DateFormatters.formatDateFull(deadline)}');

Period Reporting

// Current quarter info
final quarter = DateCalculations.getQuarter(DateTime.now());
final quarterStart = DateCalculations.startOfQuarter(DateTime.now());
final quarterEnd = DateCalculations.endOfQuarter(DateTime.now());
print('Q$quarter: ${DateFormatters.formatDateRange(quarterStart, quarterEnd)}');

// Financial year
final fyStart = DateTime(DateTime.now().year, 4, 1); // April 1st
final fyEnd = DateTime(DateTime.now().year + 1, 3, 31); // March 31st next year
final businessDaysInFY = DateCalculations.countBusinessDays(fyStart, fyEnd);
print('Business days in FY: $businessDaysInFY');

🛠️ Extending the Library

Adding New Languages

Edit lib/constants.dart:

static final Map<String, List<String>> monthNames = {
  'en': ['January', 'February', ...],
  'es': ['Enero', 'Febrero', ...],
  'it': ['Gennaio', 'Febbraio', ...], // Add Italian
};

// Also add to monthNamesShort, dayNames, dayNamesShort
// And add relative time translations in getRelativeTimeTranslations()

Adding Custom Formatters

Create your own formatter class:

import 'package:save_points_intl/datetime.dart';

class MyCustomFormatters {
  static String formatFinancialQuarter(DateTime date) {
    final quarter = DateCalculations.getQuarter(date);
    return 'FY Q$quarter ${date.year}';
  }
  
  static String formatWeekRange(DateTime date) {
    final start = DateCalculations.startOfWeek(date);
    final end = DateCalculations.endOfWeek(date);
    return DateFormatters.formatDateRange(start, end);
  }
}

📊 Performance

Benchmarks

Operation Time Memory
Format date <0.1ms Minimal
Compare dates <0.01ms None
Calculate business days ~0.1ms per day Minimal
Parse date <0.5ms Minimal
Relative time <0.1ms Minimal

Bundle Size Impact

  • Core helpers: ~35KB
  • With all languages: ~45KB
  • Single module: ~5-10KB (tree-shakable)

No runtime overhead, all calculations are pure Dart.


❓ FAQ

Why not use the `intl` package?

While intl is great, this library offers:

  • ✅ No external dependencies = no version conflicts
  • ✅ Lighter weight = faster builds
  • ✅ Fully customizable = modify for your needs
  • ✅ More business logic = calculations, comparisons, etc.
  • ✅ Simpler API = easier to use

Use intl if you need comprehensive i18n. Use this if you want lightweight date/time helpers.

Can I use this in production?

Yes! This library is:

  • Fully tested and verified
  • Zero dependencies (no breaking changes risk)
  • Type-safe with null safety
  • Well documented
  • Production-ready
How do I add more languages?

Edit lib/constants.dart and add your language to:

  1. monthNames map
  2. monthNamesShort map
  3. dayNames map
  4. dayNamesShort map
  5. getRelativeTimeTranslations() method

See Extending the Library for details.

Does it support RTL languages?

✅ Yes! Arabic is included with proper translations. The library returns formatted strings; your UI framework handles RTL display.

Can I use only specific modules?

✅ Absolutely! Import only what you need:

import 'package:save_points_intl/date_formatters.dart';
import 'package:save_points_intl/date_comparisons.dart';

The library is fully modular and tree-shakable.

How do I handle timezones?

Use the timezone utilities in DateCalculations:

// Convert to UTC
final utc = DateCalculations.toUTC(localDate);

// Convert to local
final local = DateCalculations.toLocal(utcDate);

// Get offset
final offset = DateCalculations.formatTimezoneOffset(date); // "+05:30"

🔧 Troubleshooting

Import Issues

// ❌ Wrong
import 'datetime.dart';

// ✅ Correct
import 'package:save_points_intl/datetime.dart';

Type Issues

// ❌ Wrong - nullable without handling
DateTime? date = DateParsers.parseDate('invalid');
print(date.year); // Null error!

// ✅ Correct - handle nullable
DateTime? date = DateParsers.parseDate('2025-12-01');
if (date != null) {
  print(date.year);
}

// ✅ Or use fallback
DateTime date = DateParsers.parseDate('2025-12-01') ?? DateTime.now();

Locale Not Working

// ❌ Wrong - invalid locale code
DateFormatters.formatDateLong(date, 'spanish');

// ✅ Correct - use proper locale codes
DateFormatters.formatDateLong(date, 'es_ES');
DateFormatters.formatDateLong(date, 'es'); // Also works

🤝 Contributing

Contributions are welcome! To contribute:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests if applicable
  5. Submit a pull request

Areas for Contribution

  • 🌍 More languages - Add translations for your language
  • 📝 Documentation - Improve docs, add examples
  • 🐛 Bug fixes - Report and fix issues
  • Features - Suggest and implement new features

📜 License

This library is free to use in your Flutter projects.

MIT License - Use it, modify it, share it!


🙏 Acknowledgments

  • Built with pure Dart
  • Inspired by moment.js, date-fns, and intl package
  • Community feedback and contributions

📞 Support

  • 📖 Documentation: See EXAMPLES.md for comprehensive examples
  • 🐛 Issues: Report bugs via GitHub issues
  • 💬 Discussions: Start a discussion for questions
  • Star: If you like it, give it a star!

Made with ❤️ for the Flutter community

⬆ Back to Top

# save_points_intl