flutter_relative_time 0.2.0 copy "flutter_relative_time: ^0.2.0" to clipboard
flutter_relative_time: ^0.2.0 copied to clipboard

Human-friendly past and future DateTime formatting with localized timeago and calendar labels.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_relative_time/flutter_relative_time.dart';
import 'package:intl/date_symbol_data_local.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await initializeDateFormatting();
  runApp(const RelativeTimeExampleApp());
}

class RelativeTimeExampleApp extends StatelessWidget {
  const RelativeTimeExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'flutter_relative_time example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF4E4193)),
        useMaterial3: true,
      ),
      home: const RelativeTimeExamplePage(),
    );
  }
}

class RelativeTimeExamplePage extends StatefulWidget {
  const RelativeTimeExamplePage({super.key});

  @override
  State<RelativeTimeExamplePage> createState() =>
      _RelativeTimeExamplePageState();
}

class _RelativeTimeExamplePageState extends State<RelativeTimeExamplePage> {
  static final DateTime _now = DateTime(2026, 8, 2, 12);

  String _locale = 'en_US';
  RelativeTimeClockFormat _clockFormat = RelativeTimeClockFormat.auto;

  @override
  Widget build(BuildContext context) {
    final examples = _buildExamples();

    return Scaffold(
      appBar: AppBar(title: const Text('flutter_relative_time')),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          Text(
            'Format DateTime values for future, past, calendar and very recent UI labels.',
            style: Theme.of(context).textTheme.titleMedium,
          ),
          const SizedBox(height: 20),
          _ExampleSection(
            title: 'Locale',
            child: Wrap(
              spacing: 8,
              children: [
                _ChoiceChip(
                  label: 'English US',
                  selected: _locale == 'en_US',
                  onSelected: () => setState(() => _locale = 'en_US'),
                ),
                _ChoiceChip(
                  label: 'Spanish ES',
                  selected: _locale == 'es_ES',
                  onSelected: () => setState(() => _locale = 'es_ES'),
                ),
                _ChoiceChip(
                  label: 'Portuguese BR',
                  selected: _locale == 'pt_BR',
                  onSelected: () => setState(() => _locale = 'pt_BR'),
                ),
              ],
            ),
          ),
          const SizedBox(height: 12),
          _ExampleSection(
            title: 'Clock format',
            child: Wrap(
              spacing: 8,
              runSpacing: 8,
              children: [
                _ChoiceChip(
                  label: 'Auto',
                  selected: _clockFormat == RelativeTimeClockFormat.auto,
                  onSelected: () => setState(
                    () => _clockFormat = RelativeTimeClockFormat.auto,
                  ),
                ),
                _ChoiceChip(
                  label: '12h',
                  selected: _clockFormat == RelativeTimeClockFormat.twelveHour,
                  onSelected: () => setState(
                    () => _clockFormat = RelativeTimeClockFormat.twelveHour,
                  ),
                ),
                _ChoiceChip(
                  label: '24h',
                  selected:
                      _clockFormat == RelativeTimeClockFormat.twentyFourHour,
                  onSelected: () => setState(
                    () => _clockFormat = RelativeTimeClockFormat.twentyFourHour,
                  ),
                ),
              ],
            ),
          ),
          const SizedBox(height: 20),
          for (final example in examples) ...[
            _ExampleCard(example: example),
            const SizedBox(height: 12),
          ],
        ],
      ),
    );
  }

  List<_RelativeTimeExample> _buildExamples() {
    final timeAgoOptions = RelativeTimeFormatOptions.timeAgo(now: _now);
    final calendarOptions = RelativeTimeFormatOptions.calendar(
      now: _now,
      clockFormat: _clockFormat,
    );

    return [
      _RelativeTimeExample(
        title: 'Future · time ago',
        input: 'DateTime(2026, 8, 2, 14)',
        code:
            "startsAt.toTimeAgo(locale: '$_locale', options: RelativeTimeFormatOptions.timeAgo(now: now))",
        value: DateTime(
          2026,
          8,
          2,
          14,
        ).toTimeAgo(locale: _locale, options: timeAgoOptions),
      ),
      _RelativeTimeExample(
        title: 'Future · calendar',
        input: 'DateTime(2026, 8, 3, 5, 3)',
        code:
            "tomorrow.toRelativeCalendar(locale: '$_locale', options: RelativeTimeFormatOptions.calendar(now: now, clockFormat: $_clockFormat))",
        value: DateTime(
          2026,
          8,
          3,
          5,
          3,
        ).toRelativeCalendar(locale: _locale, options: calendarOptions),
      ),
      _RelativeTimeExample(
        title: 'Past · time ago',
        input: 'DateTime(2026, 8, 2, 11, 55)',
        code:
            "createdAt.toTimeAgo(locale: '$_locale', options: RelativeTimeFormatOptions.timeAgo(now: now))",
        value: DateTime(
          2026,
          8,
          2,
          11,
          55,
        ).toTimeAgo(locale: _locale, options: timeAgoOptions),
      ),
      _RelativeTimeExample(
        title: 'Past · calendar',
        input: 'DateTime(2026, 7, 28, 18, 45)',
        code:
            "paidAt.toRelativeCalendar(locale: '$_locale', options: RelativeTimeFormatOptions.calendar(now: now, clockFormat: $_clockFormat))",
        value: DateTime(
          2026,
          7,
          28,
          18,
          45,
        ).toRelativeCalendar(locale: _locale, options: calendarOptions),
      ),
      _RelativeTimeExample(
        title: 'Very recent · past',
        input: 'DateTime(2026, 8, 2, 11, 59, 50)',
        code:
            "sentAt.toTimeAgo(locale: '$_locale', options: RelativeTimeFormatOptions.timeAgo(now: now))",
        value: DateTime(
          2026,
          8,
          2,
          11,
          59,
          50,
        ).toTimeAgo(locale: _locale, options: timeAgoOptions),
      ),
      _RelativeTimeExample(
        title: 'Very recent · future',
        input: 'DateTime(2026, 8, 2, 12, 0, 10)',
        code:
            "retryAt.toTimeAgo(locale: '$_locale', options: RelativeTimeFormatOptions.timeAgo(now: now))",
        value: DateTime(
          2026,
          8,
          2,
          12,
          0,
          10,
        ).toTimeAgo(locale: _locale, options: timeAgoOptions),
      ),
      _RelativeTimeExample(
        title: 'Nullable DateTime',
        input: 'DateTime? value = null',
        code: "value.toRelativeTime(locale: '$_locale')",
        value: null.toRelativeTime(locale: _locale),
      ),
    ];
  }
}

class _ExampleSection extends StatelessWidget {
  const _ExampleSection({required this.title, required this.child});

  final String title;
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(title, style: Theme.of(context).textTheme.titleSmall),
        const SizedBox(height: 8),
        child,
      ],
    );
  }
}

class _ChoiceChip extends StatelessWidget {
  const _ChoiceChip({
    required this.label,
    required this.selected,
    required this.onSelected,
  });

  final String label;
  final bool selected;
  final VoidCallback onSelected;

  @override
  Widget build(BuildContext context) {
    return ChoiceChip(
      label: Text(label),
      selected: selected,
      onSelected: (_) => onSelected(),
    );
  }
}

class _ExampleCard extends StatelessWidget {
  const _ExampleCard({required this.example});

  final _RelativeTimeExample example;

  @override
  Widget build(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;

    return Card(
      elevation: 0,
      color: colorScheme.surfaceContainerHighest,
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(example.title, style: Theme.of(context).textTheme.titleMedium),
            const SizedBox(height: 8),
            Text(
              example.value,
              style: Theme.of(context).textTheme.headlineSmall?.copyWith(
                color: colorScheme.primary,
                fontWeight: FontWeight.w700,
              ),
            ),
            const SizedBox(height: 12),
            _Metadata(label: 'Input', value: example.input),
            const SizedBox(height: 8),
            _Metadata(label: 'Usage', value: example.code),
          ],
        ),
      ),
    );
  }
}

class _Metadata extends StatelessWidget {
  const _Metadata({required this.label, required this.value});

  final String label;
  final String value;

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(label, style: Theme.of(context).textTheme.labelMedium),
        const SizedBox(height: 4),
        SelectableText(
          value,
          style: Theme.of(
            context,
          ).textTheme.bodySmall?.copyWith(fontFamily: 'monospace'),
        ),
      ],
    );
  }
}

class _RelativeTimeExample {
  const _RelativeTimeExample({
    required this.title,
    required this.input,
    required this.code,
    required this.value,
  });

  final String title;
  final String input;
  final String code;
  final String value;
}
1
likes
160
points
250
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Human-friendly past and future DateTime formatting with localized timeago and calendar labels.

Homepage

License

MIT (license)

Dependencies

intl

More

Packages that depend on flutter_relative_time