Add/Subtract months/years to date in dart? - flutter

I saw that in dart there is a class Duration but it cant be used add/subtract years or month. How did you managed this issue, I need to subtract 6 months from an date. Is there something like moment.js for dart or something around?
Thank you

Okay so you can do that in two steps, taken from #zoechi (a big contributor to Flutter):
Define the base time, let us say:
var date = new DateTime(2018, 1, 13);
Now, you want the new date:
var newDate = new DateTime(date.year, date.month - 1, date.day);
And you will get
2017-12-13

You can use the subtract and add methods
date1.subtract(Duration(days: 7, hours: 3, minutes: 43, seconds: 56));
date1.add(Duration(days: 1, hours: 23)));
Flutter Docs:
Subtract
Add

Try out this package, Jiffy. Adds and subtracts date time with respect to how many days there are in a month and also leap years. It follows the simple syntax of momentjs
You can add and subtract using the following units
years, months, weeks, days, hours, minutes, seconds and milliseconds
To add 6 months
DateTime d = Jiffy().add(months: 6).dateTime; // 2020-04-26 10:05:57.469367
// You can also add you own Datetime object
DateTime d = Jiffy(DateTime(2018, 1, 13)).add(months: 6).dateTime; // 2018-07-13 00:00:00.000
You can also do chaining using dart method cascading
var jiffy = Jiffy().add(months: 5, years: 1);
DateTime d = jiffy.dateTime; // 2021-03-26 10:07:10.316874
// you can also format with ease
String s = jiffy.format("yyyy, MMM"); // 2021, Mar
// or default formats
String s = jiffy.yMMMMEEEEdjm; // Friday, March 26, 2021 10:08 AM

You can use subtract and add methods
Subtract
Add
But you have to reassign the result to the variable, which means:
This wouldn't work
date1.add(Duration(days: 1, hours: 23)));
But this will:
date1 = date1.add(Duration(days: 1, hours: 23)));
For example:
void main() {
var d = DateTime.utc(2020, 05, 27, 0, 0, 0);
d.add(Duration(days: 1, hours: 23));
// the prev line has no effect on the value of d
print(d); // prints: 2020-05-27 00:00:00.000Z
//But
d = d.add(Duration(days: 1, hours: 23));
print(d); // prints: 2020-05-28 23:00:00.000Z
}
Dartpad link

In simple way without using any lib you can add Month and Year
var date = new DateTime(2021, 1, 29);
Adding Month :-
date = DateTime(date.year, date.month + 1, date.day);
Adding Year :-
date = DateTime(date.year + 1, date.month, date.day);

Not so simple.
final date = DateTime(2017, 1, 1);
final today = date.add(const Duration(days: 1451));
This results in 2020-12-21 23:00:00.000 because Dart considers daylight to calculate dates (so my 1451 days is missing 1 hour, and this is VERY dangerous (for example: Brazil abolished daylight savings in 2019, but if the app was written before that, the result will be forever wrong, same goes if the daylight savings is reintroduced in the future)).
To ignore the dayligh calculations, do this:
final date = DateTime(2017, 1, 1);
final today = DateTime(date.year, date.month, date.day + 1451);
Yep. Day is 1451 and this is OK. The today variable now shows the correct date and time: 2020-12-12 00:00:00.000.

It's pretty straightforward.
Simply add or subtract with numbers on DateTime parameters based on your requirements.
For example -
~ Here I had a requirement of getting the date-time exactly 16 years before today even with milliseconds and in the below way I got my solution.
DateTime today = DateTime.now();
debugPrint("Today's date is: $today"); //Today's date is: 2022-03-17 09:08:33.891843
After desired subtraction;
DateTime desiredDate = DateTime(
today.year - 16,
today.month,
today.day,
today.hour,
today.minute,
today.second,
today.millisecond,
today.microsecond,
);
debugPrint("16 years ago date is: $desiredDate"); // 16 years before date is: 2006-03-17 09:08:33.891843

Increase and Decrease of the day/month/year can be done by DateTime class
Initialise DateFormat which needed to be shown
var _inputFormat = DateFormat('EE, d MMM yyyy');
var _selectedDate = DateTime.now();
Increase Day/month/year:
_selectedDate = DateTime(_selectedDate.year,
_selectedDate.month + 1, _selectedDate.day);
Increase Day/month/year:
_selectedDate = DateTime(_selectedDate.year,
_selectedDate.month - 1, _selectedDate.day);
Above example is for only month, similar way we can increase or decrease year and day.

Can subtract any count of months.
DateTime subtractMonths(int count) {
var y = count ~/ 12;
var m = count - y * 12;
if (m > month) {
y += 1;
m = month - m;
}
return DateTime(year - y, month - m, day);
}
Also works
DateTime(date.year, date.month + (-120), date.day);

Future<void> main() async {
final DateTime now = DateTime.now();
var kdate = KDate.buildWith(now);
log("YEAR", kdate.year);
log("MONTH", kdate.month);
log("DATE", kdate.date);
log("Last Year", kdate.lastYear);
log("Last Month", kdate.lastMonth);
log("Yesturday", kdate.yesturday);
log("Last Week Date", kdate.lastWeekDate);
}
void log(title, data) {
print("\n$title ====> $data");
}
class KDate {
KDate({
this.now,
required this.year,
required this.month,
required this.date,
required this.lastYear,
required this.lastMonth,
required this.yesturday,
required this.lastWeekDate,
});
final DateTime? now;
final String? year;
final String? month;
final String? date;
final String? lastMonth;
final String? lastYear;
final String? yesturday;
final String? lastWeekDate;
factory KDate.buildWith(DateTime now) => KDate(
now: now,
year: (now.year).toString().split(" ")[0],
month: (now.month).toString().split(" ")[0],
date: (now.day).toString().split(" ")[0],
lastYear: (now.year - 1).toString().split(" ")[0],
lastMonth: DateTime(now.year, now.month, now.month)
.subtract(Duration(days: 28))
.toString()
.split(" ")[0]
.toString()
.split("-")[1],
yesturday: DateTime(now.year, now.month, now.day)
.subtract(Duration(days: 1))
.toString()
.split(" ")[0]
.toString()
.split("-")
.last,
lastWeekDate: DateTime(now.year, now.month, now.day)
.subtract(Duration(days: 7))
.toString()
.split(" ")[0]
.toString()
.split("-")
.last,
);
}

I'm a fan of using extensions in dart, and we can use them here like this:
extension DateHelpers on DateTime {
DateTime copyWith({
int? year,
int? month,
int? day,
int? hour,
int? second,
int? millisecond,
int? microsecond,
}) {
return DateTime(
year ?? this.year,
month ?? this.month,
day ?? this.day,
hour ?? this.hour,
second ?? this.second,
millisecond ?? this.millisecond,
microsecond ?? this.microsecond,
);
}
DateTime addYears(int years) {
return copyWith(year: this.year + years);
}
DateTime addMonths(int months) {
return copyWith(month: this.month + months);
}
DateTime addWeeks(int weeks) {
return copyWith(day: this.day + weeks*7);
}
DateTime addDays(int days) {
return copyWith(day: this.day + days);
}
}
You can then use this utility code as follows:
final now = DateTime.now();
final tomorrow = now.addDays(1);
final nextWeek = now.addWeeks(1);
final nextMonth = now.addMonths(1);
final nextYear = now.addYears(1);

Related

How to get the first, second, third, and fourth week of the month?

I want to get all four weeks (first and last day date) on the current month with Monday as the start of the week.
I can only figure out how to get the current week's first and last date with this code:
var firstDayOfTheWeek = DateTime.now().subtract(Duration(days: DateTime.now().weekday - 1));
var lastDayOfTheWeek = DateTime.now().add(Duration(days: DateTime.daysPerWeek - DateTime.now().weekday));
Thanks in advance!
Below method return next weekday's DateTime what you want from now or specific day.
DateTime getNextWeekDay(int weekDay, {DateTime from}) {
DateTime now = DateTime.now();
if (from != null) {
now = from;
}
int remainDays = weekDay - now.weekday + 7;
return now.add(Duration(days: remainDays));
}
The weekday parameter can be came like below DateTime const value or just int value.
class DateTime {
...
static const int monday = 1;
static const int tuesday = 2;
static const int wednesday = 3;
static const int thursday = 4;
static const int friday = 5;
static const int saturday = 6;
static const int sunday = 7;
...
}
If you want to get next Monday from now, call like below.
DateTime nextMonday = getNextWeekDay(DateTime.monday);
If you want to get next next Monday from now, call like below.
Or you just add 7 days to 'nextMonday' variable.
DateTime nextMonday = getNextWeekDay(DateTime.monday);
DateTime nextNextMonday = getNextWeekDay(DateTime.monday, from: nextMonday);
or
DateTime nextNextMonday = nextMonday.add(Duration(days: 7));

How to get a list of each week in a time range with Dart?

I am trying to build a weeks-timeline in my Flutter app.
I am trying to generate a list of all of the weeks in a given time range (for example December 2020 - December 2021).
Each week will be a list by itself, which will hold the days. Something like this:
[
[
{
dayName: 'Sunday',
date: 'December 13 2020',
},
{
dayName: 'Monday',
date: 'December 14 2020',
},
{
dayName: 'Tuesday',
date: 'December 15 2020',
},
{
dayName: 'Wednesday',
date: 'December 16 2020',
},
{
dayName: 'Thursday',
date: 'December 17 2020',
},
{
dayName: 'Friday',
date: 'December 18 2020',
},
{
dayName: 'Saturday',
date: 'December 19 2020',
},
],
//Another Week Array
//Another Week Array
//Etc
]
Does anyone know how can I achieve this type of data in Dart and Flutter?
Thank you!
As Stefano wrote, it's good to create a class with a structure to be able to achieve your goals. My suggestion is a little more simple since I just wrote a method you could use. You could even create an extension on the DateTime class and use that in the future, or implement it in a static class, or add it to an instance class. Here is the complete example that works on DartPad:
void main() {
var weeks = getWeeksForRange(DateTime.utc(2020,08,12), DateTime.utc(2020,10,12));
print(weeks);
}
List<List<DateTime>> getWeeksForRange(DateTime start, DateTime end) {
var result = List<List<DateTime>>();
var date = start;
var week = List<DateTime>();
while(date.difference(end).inDays <= 0) {
// start new week on Monday
if (date.weekday == 1 && week.length > 0) {
print('Date $date is a Monday');
result.add(week);
week = List<DateTime>();
}
week.add(date);
date = date.add(const Duration(days: 1));
}
result.add(week);
return result;
}
This method can take any two dates and create a list of lists (weeks) of DateTime objects. Since in the result you will have many DateTime results, you can then map them however you want since they will have all information about its date, year, weekday and will keep the formatting feature.
One first step could be to create a Class according to your needs:
class Day {
final DateTime dateTime;
Day({
this.dateTime,
});
String get day => DateFormat('EEEE').format(dateTime);
String get date => DateFormat('yMMMd').format(dateTime);
Map<String, String> toMap() => {'dayName': day, 'date': date};
}
We can construct the Class above just with a DateTime and from it, we can derive the day and date using DateFormat in the getters:
String get day => DateFormat('EEEE').format(dateTime); // returns "Friday" for example
String get date => DateFormat('yMMMd').format(dateTime); // returns "Jun 13, 2021" for example
The toMap() method allows use to easily convert the Class to a Map<String, String>:
Map<String, String> toMap() => {'dayName': day, 'date': date};
We now need to store the Days in a List<Day>:
List<Day> days = [];
By iterating from the starting DateTime to the ending DateTime:
DateTime now = DateTime.now(); // as an example
DateTime start = now;
DateTime after = now.add(Duration(days: 180));
DateTime iterator = start;
List<Day> days = [];
while (iterator.isBefore(after)) {
days.add(Day(dateTime: iterator));
iterator = iterator.add(Duration(days: 1));
}
A full source code for the scenario outlined can be found below:
import 'package:intl/intl.dart';
class Day {
final DateTime dateTime;
Day({
this.dateTime,
});
String get day => DateFormat('EEEE').format(dateTime);
String get date => DateFormat('yMMMd').format(dateTime);
String toString() =>
'\t{\n\t\t"dayName": "$day",\n\t\t"date": "$date"\n\t}\n';
Map<String, String> toMap() => {'dayName': day, 'date': date};
}
void main() {
DateTime now = DateTime.now();
DateTime start = now;
DateTime after = now.add(Duration(days: 180));
DateTime iterator = start;
List<Day> days = [];
while (iterator.isBefore(after)) {
days.add(Day(dateTime: iterator));
iterator = iterator.add(Duration(days: 1));
}
print(days);
}
If you'd like to group the Days by week, we'll then need a multi-dimensional List:
void main() {
DateTime now = DateTime.now();
DateTime start = now;
DateTime after = now.add(Duration(days: 180));
DateTime iterator = start;
List<List<Day>> days = [[]]; // multi-dimensional List
int i = 0;
while (iterator.isBefore(after)) {
if (days[i].isEmpty) days.add([]); // init of the week List
days[i].add(Day(dateTime: iterator));
if (iterator.weekday == 7) i++; // new week
iterator = iterator.add(Duration(days: 1));
}
print(days);
}

How to only change the time in DateTime?

I have a DateTime and I'm trying to do two things with it. 1: Only update the date and month. 2: Only update the time. How can I achieve that?
DateTime currentDateTime = DateTime.now();
void updateTime(DateTime newTime) {
currentDateTime = ?
}
void updateDate(DateTime newTime) {
currentDateTime = ?
}
Is there any way I can destruct the currentDateTime like DateTime(...currentDateTime, ..newTime)
Construct your Datetime object from Datetime.now() properties, instead of the whole Datetime.now() object. This should work.
DateTime currentDateTime = DateTime.now();
void updateTime(DateTime currentDateTime, DateTime newTime) {
currentDateTime = DateTime(
year: currentDateTime.year,
month: currentDateTime.month
day: currentDateTime.day,
hour: newTime.hour,
minute: newTime.minute,
second: newTime.second,
);
}
void updateDate(DateTime currentDateTime, DateTime newDate) {
currentDateTime = DateTime(
year: currentDateTime.year,
month: newTime.month
day: newTime.day,
hour: currentDateTime.hour,
minute: currentDateTime.minute,
second: currentDateTime.second,
);
}
Remember the constructor of Datetime looks like this
DateTime(int year, [int month = 1, int day = 1, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0])
To only update time you can use TimeOfDay. This is approach that I can do
DateTime currentDateTime = DateTime.now();
void updateTime(TimeOfDay newTime) {
// 2020-09-07 09:03:24.469
TimeOfDay time = TimeOfDay(hour: newTime.hour, minute: newTime.minute);
currentDateTime = DateTime(currentDateTime.year, currentDateTime.month, currentDateTime.month, time.hour, time.minute);
// 2020-09-09 15:00:00.000
}
void updateDate(DateTime newTime) {
// 2020-09-09 15:00:00.000
currentDateTime = DateTime(newTime.year, newTime.month, newTime.day);
// 2021-01-01 00:00:00.000
}
I hope this is helpful.

How to display time ago like Youtube in Flutter

I'm writing a flutter app to clone some Youtube functionalities using Youtube API V3.
The app fetches video timestamp as a String from youtube video API
Each timestamp has this format :
YYYY-MM-DDTHH:MM:SSZ
One example would be:
2020-07-12T20:42:19Z
I would like to display in a text :
1 hour
1 hours ago
4 weeks ago
11 months ago
1 year ago
...
I've created an extension on String
extension StringExtension on String {
static String displayTimeAgoFromTimestamp(String timestamp) {
final year = int.parse(timestamp.substring(0, 4));
final month = int.parse(timestamp.substring(5, 7));
final day = int.parse(timestamp.substring(8, 10));
final hour = int.parse(timestamp.substring(11, 13));
final minute = int.parse(timestamp.substring(14, 16));
final DateTime videoDate = DateTime(year, month, day, hour, minute);
final int diffInHours = DateTime.now().difference(videoDate).inHours;
String timeAgo = '';
String timeUnit = '';
int timeValue = 0;
if (diffInHours < 1) {
final diffInMinutes = DateTime.now().difference(videoDate).inMinutes;
timeValue = diffInMinutes;
timeUnit = 'minute';
} else if (diffInHours < 24) {
timeValue = diffInHours;
timeUnit = 'hour';
} else if (diffInHours >= 24 && diffInHours < 24 * 7) {
timeValue = (diffInHours / 24).floor();
timeUnit = 'day';
} else if (diffInHours >= 24 * 7 && diffInHours < 24 * 30) {
timeValue = (diffInHours / (24 * 7)).floor();
timeUnit = 'week';
} else if (diffInHours >= 24 * 30 && diffInHours < 24 * 12 * 30) {
timeValue = (diffInHours / (24 * 30)).floor();
timeUnit = 'month';
} else {
timeValue = (diffInHours / (24 * 365)).floor();
timeUnit = 'year';
}
timeAgo = timeValue.toString() + ' ' + timeUnit;
timeAgo += timeValue > 1 ? 's' : '';
return timeAgo + ' ago';
}
}
Then call in text:
StringExtension.displayTimeAgoFromTimestamp(video.timestamp)
You can use the timeago package
example code below
import 'package:timeago/timeago.dart' as timeago;
main() {
final fifteenAgo = new DateTime.now().subtract(new Duration(minutes: 15));
print(timeago.format(fifteenAgo)); // 15 minutes ago
print(timeago.format(fifteenAgo, locale: 'en_short')); // 15m
print(timeago.format(fifteenAgo, locale: 'es')); // hace 15 minutos
}
to use it with the YYYY-MM-DDTHH:MM:SSZ time format you can convert the String to a DateTime then perform the operation on the DateTime variable
DateTime time = DateTime.parse("2020-07-12T20:42:19Z");
print(timeago.format(time));
I've created reusable function for sample, this might be helpful!!
import 'package:intl/intl.dart';
//for DateTime manipulation need to add this package
import 'package:timeago/timeago.dart' as timeago;
void main(){
//creating this getTimeAgo function to format dateTime with user inputs
dynamic getTimeAgo(DateTime d) {
dynamic value = "";
//setting current time variable now
final now = DateTime.now();
//converting the user provided date to LocalTime
final recvDate = d.toLocal();
//declaring today's date in today variable
final today = DateTime(now.year, now.month, now.day);
//declaring yesterday's date in yesterday variable
final yesterday = DateTime(now.year, now.month, now.day - 1);
//declaring user provided date's in date variable
final date = DateTime(recvDate.year, recvDate.month, recvDate.day);
//comparing today's date is equal to user provided date then return value with timeAgo flutter package response
if (date == today) {
final curtimeNow = timeago.format(d);
if (curtimeNow == 'a day ago') {
value = "1 day ago";
} else if (curtimeNow == 'about an hour ago') {
value = "1 hour ago";
} else {
value = curtimeNow;
}
} //comparing yesterday's date is equal to user provided date then return 1 day ago
else if (date == yesterday) {
value='1 day ago';
} //else the user provided date then return as the date format of dd MMM yyyy Eg. 10 Mar 2022
else {
value = DateFormat('dd MMM yyyy').format(date);
}
//returning the response
return value;
}
//declaring the date which is to used be formatted
var recvdDateTime=DateTime.now().subtract(Duration(minutes: 45));;
//calling the getTimeAgo (fn) with user input
getTimeAgo(DateTime.parse(recvdDateTime));
}

Get current Week of the Month as a Number

How do I get the current week of the month as a number in Dart? I need to create some sort of calender with a week view where it says something like "2. Week of January"
You can use DateTime().now() to get the current time and date of the system or today's date also. Here is the code snippet below:
// Current date and time of system
String date = DateTime.now().toString();
// This will generate the time and date for first day of month
String firstDay = date.substring(0, 8) + '01' + date.substring(10);
// week day for the first day of the month
int weekDay = DateTime.parse(firstDay).weekday;
DateTime testDate = DateTime.now();
int weekOfMonth;
// If your calender starts from Monday
weekDay--;
weekOfMonth = ((testDate.day + weekDay) / 7).ceil();
print('Week of the month: $weekOfMonth');
weekDay++;
// If your calender starts from sunday
if (weekDay == 7) {
weekDay = 0;
}
weekOfMonth = ((testDate.day + weekDay) / 7).ceil();
print('Week of the month: $weekOfMonth');
Alternatively, if are looking for a complete implementation of the calender month UI then click here
My Answer is impaired from #dblank answer
extension DateTimeExtension on DateTime {
int get weekOfMonth {
var date = this;
final firstDayOfTheMonth = DateTime(date.year, date.month, 1);
int sum = firstDayOfTheMonth.weekday - 1 + date.day;
if (sum % 7 == 0) {
return sum ~/ 7;
} else {
return sum ~/ 7 + 1;
}
}
}
Then use it like this:
var wom = DateTime.now().weekOfMonth;
extension DateTimeExtension on DateTime {
int get weekOfMonth {
var wom = 0;
var date = this;
while (date.month == month) {
wom++;
date = date.subtract(const Duration(days: 7));
}
return wom;
}
}
Then use it like this:
var wom = DateTime.now().weekOfMonth;