Flutter - How to find difference between two dates in years, months and days?
Asked Answered
H

15

12

I'm looking for a way to use DateTime to parse two dates, to show the difference. I want to have it on the format: "X years, Y months, Z days".

For JS, we have momentjs library and following code::

var a = moment([2015, 11, 29]);
var b = moment([2007, 06, 27]);

var years = a.diff(b, 'year');
b.add(years, 'years');

var months = a.diff(b, 'months');
b.add(months, 'months');

var days = a.diff(b, 'days');

console.log(years + ' years ' + months + ' months ' + days + ' days');
// 8 years 5 months 2 days

Is there similar library available for dart that can help achieve this usecase?

However answered 3/6, 2020 at 10:13 Comment(0)
V
11

I think it is not possible to do exactly what you want easily with DateTime. Therefore you can use https://pub.dev/packages/time_machine package that is quite powerful with date time handling:

import 'package:time_machine/time_machine.dart';

void main() {
  LocalDate a = LocalDate.today();
  LocalDate b = LocalDate.dateTime(DateTime(2022, 1, 2));
  Period diff = b.periodSince(a);
  print("years: ${diff.years}; months: ${diff.months}; days: ${diff.days}");
}

for hours/minutes/seconds precision:

import 'package:time_machine/time_machine.dart';

void main() {
  LocalDateTime a = LocalDateTime.now();
  LocalDateTime b = LocalDateTime.dateTime(DateTime(2022, 1, 2, 10, 15, 47));
  Period diff = b.periodSince(a);
  print("years: ${diff.years}; months: ${diff.months}; days: ${diff.days}; hours: ${diff.hours}; minutes: ${diff.minutes}; seconds: ${diff.seconds}");
}
Visigoth answered 3/6, 2020 at 10:36 Comment(2)
How would you extend this to get hours minutes and seconds?Postliminy
time_machine hasn't been updated in 2+ years at this point.Merissa
T
9

What you are looking for is the Dart DateTime class You can get close to what you want in moment.js with

main() {
  var a = DateTime.utc(2015, 11, 29);
  var b = DateTime.utc(2007, 06, 27);

  var years = a.difference(b);
  print(years.inDays ~/365);

}

There is no inYears or inMonths option for DateTime though that's why the year is divided in the print. the difference function returns the difference in seconds so you have to process it yourself to days.

Teucer answered 3/6, 2020 at 10:31 Comment(2)
Nice one! ThanksPaddock
This one is actually the best answerAcetylcholine
L
4

You can calculate from the total number of days:

void main() {
  DateTime a = DateTime(2015, 11, 29);
  DateTime b = DateTime(2007, 06, 27);
  int totalDays = a.difference(b).inDays;
  int years = totalDays ~/ 365;
  int months = (totalDays-years*365) ~/ 30;
  int days = totalDays-years*365-months*30;
  print("$years $months $days $totalDays");
}

Result is: 8 5 7 3077

Lagos answered 3/6, 2020 at 10:31 Comment(3)
Required difference in year, month and days. read question carefullyOverbalance
@AbdulQadir from number of days you can easily calculate the other numbers; I added some code to show.Lagos
months calculation is obviously wrong.Merissa
H
3

You can use Jiffy Package for this like this

var jiffy1 = Jiffy("2008-10", "yyyy-MM");
var jiffy2 = Jiffy("2007-1", "yyyy-MM");

jiff1.diff(jiffy2, Units.YEAR); // 1
jiff1.diff(jiffy2, Units.YEAR, true);
Helsinki answered 13/1, 2021 at 7:44 Comment(1)
I have run into two really serious bugs in Jiffy so far (the worst of the two was that the Z suffix of ISO 8601 strings was being ignored, meaning date/time strings were being parsed as local DateTime instances, rather than in UTC, which put the time off by many hours). This is in version 6.3.0 of the library. If Jiffy can't get things this important right, I have absolutely no faith in it anymore. I am in the process of removing Jiffy from all my code. See my answer for my own pure Dart solution to the OP's question.Merissa
D
2

You could write an extension on duration class to format it:

extension DurationExtensions on Duration {
  String toYearsMonthsDaysString() {
    final years = this.inDays ~/ 365
    // You will need a custom logic for the months part, since not every month has 30 days
    final months = (this.inDays ~% 365) ~/ 30
    final days = (this.inDays ~% 365) ~% 30

    return "$years years $months months $days days";
  }
}

The usage will be:

final date1 = DateTime()
final date2 = DateTime()
date1.difference(date2).toYearsMonthsDaysString()
Declarant answered 3/6, 2020 at 11:7 Comment(0)
H
2

I created my own class for Gregorian Dates, and I created a method which handle this issue, it calculates "logically" the difference between two dates in years, months, and days... i actually created the class from scratch without using any other packages (including DateTime package) but here I used DateTime package to illustrate how this method works.. until now it works fine for me...

method to determine if it's a leap year or no:

    static bool leapYear(DateTime date) {
    if(date.year%4 == 0) {
      if(date.year%100 == 0){
        return date.year%400 == 0;
      }
      return true;
    }
    return false;
  }

this is the method which calculates the difference between two dates in years, months, and days. it puts the result in a list of integers:

     static List<int> differenceInYearsMonthsDays(DateTime dt1, DateTime dt2) {
    List<int> simpleYear = [31,28,31,30,31,30,31,31,30,31,30,31];
    if(dt1.isAfter(dt2)) {
      DateTime temp = dt1;
      dt1 = dt2;
      dt2 = temp;
    }
    int totalMonthsDifference = ((dt2.year*12) + (dt2.month - 1)) - ((dt1.year*12) + (dt1.month - 1));
    int years = (totalMonthsDifference/12).floor();
    int months = totalMonthsDifference%12;
    late int days;
    if(dt2.day >= dt1.day) {days = dt2.day - dt1.day;}
    else {
      int monthDays = dt2.month == 3
          ? (leapYear(dt2)? 29: 28)
          : (dt2.month - 2 == -1? simpleYear[11]: simpleYear[dt2.month - 2]);
      int day = dt1.day;
      if(day > monthDays) day = monthDays;
      days = monthDays - (day - dt2.day);
      months--;
    }
    if(months < 0) {
      months = 11;
      years--;
    }
    return [years, months, days];
  }

the method which calculates the difference between two dates in months, and days:

static List<int> differenceInMonths(DateTime dt1, DateTime dt2){
    List<int> inYears = differenceInYearsMonthsDays(dt1, dt2);
    int difMonths = (inYears[0]*12) + inYears[1];
    return [difMonths, inYears[2]];
  }

the method which calculates the difference between two dates in days:

static int differenceInDays(DateTime dt1, DateTime dt2) {
    if(dt1.isAfter(dt2)) {
      DateTime temp = dt1;
      dt1 = dt2;
      dt2 = temp;
    }
    return dt2.difference(dt1).inDays;
  }

usage example:

void main() {
  DateTime date1 = DateTime(2005, 10, 3);
  DateTime date2 = DateTime(2022, 1, 12);
  List<int> diffYMD = GregorianDate.differenceInYearsMonthsDays(date1, date2);
  List<int> diffMD = GregorianDate.differenceInMonths(date1, date2);
  int diffD = GregorianDate.differenceInDays(date1, date2);

  print("The difference in years, months and days: ${diffYMD[0]} years, ${diffYMD[1]} months, and ${diffYMD[2]} days.");
  print("The difference in months and days: ${diffMD[0]} months, and ${diffMD[1]} days.");
  print("The difference in days: $diffD days.");
}

output:

The difference in years, months and days: 16 years, 3 months, and 9 days.
The difference in months and days: 195 months, and 9 days.
The difference in days: 5945 days.
Huysmans answered 12/1, 2022 at 16:53 Comment(0)
L
2

try intl package with the following code:

import 'package:intl/intl.dart';

String startDate = '01/01/2021';
String endDate = '01/01/2022';

final start = DateFormat('dd/MM/yyyy').parse(startDate);
final end = DateFormat('dd/MM/yyyy').parse(endDate);

Then, you can calculate the duration between the two dates with the following code:

final duration = end.difference(start);

To obtain the number of years, months and days, you can do the following:

final years = duration.inDays / 365;
final months = duration.inDays % 365 / 30;
final days = duration.inDays % 365 % 30;

Finally, you can use these variables to display the result in the desired format:

    final result = '${years.toInt()} years ${months.toInt()} months y ${days.toInt()} days';
Log answered 2/1, 2023 at 1:13 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Steam
B
1

the answer is yes, you can easilly achieve it with DateTime class in Dart. See: https://api.dart.dev/stable/2.8.3/dart-core/DateTime-class.html

Example

void main() {
  var moonLanding = DateTime(1969,07,20)
  var marsLanding = DateTime(2024,06,10);
  var diff = moonLanding.difference(marsLanding);

  print(diff.inDays.abs());
  print(diff.inMinutes.abs());
  print(diff.inHours.abs());
}

outputs: 20049 28870560 481176

Buntline answered 3/6, 2020 at 10:31 Comment(3)
indays() will give the total duration in days, so is inhours() and in mitutes(). in order to get te result you need, you need to divide the inDays() with 365 (for years). like wise apply logic for months and days,Harquebusier
yeah, agree here, it requires some additional computation to get years and months. Can be Alex answer using time_machine lib below is more suitable to get exact numbers. But for approximate data +- 1 day I would say multiplying days by 30 and years by 365 days could also serve, depending on the use case.Buntline
Dividing by 365 will not be leap-year compliant! You'll be off by approx. 10 days every 40 years if my experimentation is anything to go by.Jeminah
K
1
final firstDate = DateTime.now();
final secondDate = DateTime(firstDate.year, firstDate.month - 20);

final yearsDifference = firstDate.year - secondDate.year;
final monthsDifference = (firstDate.year - secondDate.year) * 12 +
    firstDate.month - secondDate.month;
final totalDays = firstDate.difference(secondDate).inDays;

Simple approach, no packages needed.

Kotz answered 29/12, 2021 at 14:54 Comment(0)
R
0

DateTime difference in years is a specific function, like this:

  static int getDateDiffInYear(DateTime dateFrom, DateTime dateTo) {
    int sign = 1;
    if (dateFrom.isAfter(dateTo)) {
      DateTime temp = dateFrom;
      dateFrom = dateTo;
      dateTo = temp;
      sign = -1;
    }
    int years = dateTo.year - dateFrom.year;
    int months = dateTo.month - dateFrom.month;
    if (months < 0) {
      years--;
    } else {
      int days = dateTo.day - dateFrom.day;
      if (days < 0) {
        years--;
      }
    }
    return years * sign;
  }
Romanticize answered 21/6, 2022 at 18:15 Comment(0)
S
0

The Answer might be a little long but will give you what you need.

This will give you the values as a String in the format "Year : year, Months: month, Days: days". You can change it according to your need.

You need to call differenceInYearsMonthsAndDays() and pass the startDate and endDate.

An Extension to calculate the differents in Months discarding the excess days.

extension DateTimeUtils on DateTime {
  int differenceInMonths(DateTime other) {
    if (isAfter(other)) {
      if (year > other.year) {
        if (day >= other.day) {
          return (12 + month) - other.month;
        } else {
          return (12 + month - 1) - other.month;
        }
      } else {
        if (day >= other.day) {
          return month - other.month;
        } else {
          return month - 1 - other.month;
        }
      }
    } else {
      return 0;
    }
  }
}

A Method to generate the Year, Month and Day Format

String differenceInYearsMonthsAndDays(
  DateTime startDate,
  DateTime endDate,
) {
  int days;
  final newStartDate = startDate.add(const Duration(days: -1));
  int months = endDate.differenceInMonths(newStartDate);
  if(months >= 12) {
    final years = months ~/ 12;
    final differenceInMonthsAndDays = differenceInMonthsAndDays(
          startDate.add(const Duration(year: years), 
          endDate,
    );
    return "Years : years, $differenceInMonthsAndDays";
  } else {
    return differenceInMonthsAndDays(
          startDate, 
          endDate,
    );
  }

}

A Method to generate the Month and Day Format

String differenceInMonthsAndDays(
  DateTime startDate,
  DateTime endDate,
) {
  int days;
  final newStartDate = startDate.add(const Duration(days: -1));
  int months = endDate.differenceInMonths(newStartDate);


  if (months > 0) {
    final tempDate = DateTime(
      newStartDate.year,
      newStartDate.month + months,
      newStartDate.day,
    );
    days = endDate.difference(tempDate).inDays;
    return days > 0 
       ? "Months : $months, Days : $days" 
       : "Months : $months";
  } else {
    days = endDate.difference(newStartDate).inDays;
    return "Days : $days";
  }
}
Savell answered 12/3, 2023 at 14:20 Comment(0)
B
0

Years and months are somewhat of a special case. Most of the replies above do not account for leap years (not all years have 365 days so dividing by it might give you wrong results in some cases) and the fact that not all months are 30 days long..

The easiest way I found to calculate number of years that passed since a certain date is following:

int _getYearDifference(DateTime from, DateTime to) {
    var diff = to.year - from.year;
    if (to.month < from.month || (to.month == from.month && to.day < from.day)) {
        diff--;
    }
    return diff;
}

Similarly for months:

int _getMonthDifference(DateTime from, DateTime to) {
  int yearDiff = to.year - from.year;
  int monthDiff = max(to.month - from.month, 0);

  int diff = yearDiff * 12 + monthDiff;

  if (monthDiff > 0 && to.day < from.day) {
    diff--;
  }

  return diff;
}

For days and shorter intervals you can use the standard difference() method:

var diff = to.difference(from);
print(diff.inDays.abs());
Bogtrotter answered 29/3, 2023 at 2:19 Comment(0)
C
0
final DateTime now = DateTime.now();
final DateTime end = DateTime(2030);
int seconds = 0;
int minutes = 0;
int hours = 0;
int days = 0;
int months = 0;
int years = 0;

final Duration remainedDuration = end.difference(now);

void calculateDiff() {
      seconds = remainedDuration.inSeconds;
      minutes = seconds ~/ 60;
      seconds = seconds % 60;
      if (minutes < 60) return;
      hours = minutes ~/ 60;
      minutes = minutes % 60;
      if (hours < 24) return;
      days = hours ~/ 24;
      hours = hours % 60;
      if (days < 30) return;
      months = days ~/ 30;
      days = days % 30;
      if (months < 12) return;
      years = months ~/ 12;
      months = months % 12;
}

calculateDiff();
Cumine answered 9/3 at 10:30 Comment(0)
M
0

Here is a pure Dart solution for the missing DateTime.difference(otherDateTime).inYears (and also .inWeeks / .inMonths).

This calculates actual calendar measurements, without taking shortcuts like assuming that a year is 365.25 days long or a month is 30.44 days long.

(Note that months is total months (including years * 12) -- it doesn't represent calendar months after years have been subtracted.)

class DateTimeElapsed {
  final DateTime end;
  final DateTime start;
  late final int years;
  late final int months;
  late final int weeks;
  late final int days;
  late final int hours;
  late final int minutes;
  late final int seconds;

  DateTimeElapsed({
    required this.end,
    required this.start,
  }) {
    final outOfOrder = end.isBefore(start);
    final sign = outOfOrder ? -1 : 1;
    final startToUse = (outOfOrder ? end : start).toUtc();
    final endToUse = (outOfOrder ? start : end).toUtc();
    final endYear = endToUse.year;
    final endMonth = endToUse.month;
    final endDay = endToUse.day;
    final startYear = startToUse.year;
    final startMonth = startToUse.month;
    final startDay = startToUse.day;
    years = sign *
        (endYear -
            startYear -
            (endMonth > startMonth ||
                    (endMonth == startMonth && endDay >= startDay)
                ? 0
                : 1));
    months = sign *
        (endMonth - startMonth - (endDay >= startDay ? 0 : 1) + years * 12);
    final diff = endToUse.difference(startToUse);
    days = sign * diff.inDays;
    hours = sign * diff.inHours;
    minutes = sign * diff.inMinutes;
    seconds = sign * diff.inSeconds;
  }
}

As a bonus, here is a routine that uses the above DateTimeElapsed class to show a human-readable version of the time elapsed between two DateTime instances (either in short form, as shown on WhatsApp message timestamps or Instagram posts, or in long form):

String howLongAgo({
  required DateTime dateTime,
  required bool shortForm,
}) {
  final now = DateTime.now();
  if (now.isBefore(dateTime)) {
    return shortForm ? 'future' : 'In the future';
  }
  final diff = DateTimeElapsed(end: now, start: dateTime);
  if (diff.seconds < 60 || diff.minutes < 1) {
    return shortForm ? 'now' : 'Just now';
  }
  if (diff.minutes < 60) {
    return shortForm
        ? '${diff.minutes} min'
        : diff.minutes == 1
            ? '1 minute ago'
            : '${diff.minutes} minutes ago';
  }
  if (diff.hours < 24) {
    return shortForm
        ? '${diff.hours}h'
        : diff.hours == 1
            ? '1 hour ago'
            : '${diff.hours} hours ago';
  }
  if (diff.days < 7) {
    return shortForm
        ? '${diff.days}d'
        : diff.days == 1
            ? '1 day ago'
            : '${diff.days} days ago';
  }
  if (diff.weeks < 4) {
    return shortForm
        ? '${diff.weeks}w'
        : diff.weeks == 1
            ? '1 week ago'
            : '${diff.weeks} weeks ago';
  }
  if (diff.months < 12) {
    return shortForm
        ? '${diff.months}m'
        : diff.months == 1
            ? '1 month ago'
            : '${diff.months} months ago';
  }
  return shortForm
      ? '${diff.years}y'
      : diff.years == 1
          ? '1 year ago'
          : '${diff.years} years ago';
}

Obviously this code does not implement any sort of localization.

Merissa answered 2/7 at 19:19 Comment(0)
M
-2
difHour = someDateTime.difference(DateTime.now()).inHours;
    difMin = (someDateTime.difference(DateTime.now()).inMinutes)-(difHour*60);

and same for years and days

Mode answered 7/5, 2021 at 17:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.