A Flutter package for using Jalali (Shamsi, Solar, Persian or Jalaali) calendar. You can convert, format and manipulate Jalali and Gregorian (Miladi) dates.

Overview

A Flutter package for using Jalali (Shamsi, Solar, Persian, شمسی or خورشیدی) date. You can convert, format and manipulate Jalali and Georgian dates.

pub build coverage

This is a pure dart package and Algorithm is based on popular JavaScript library jalaali-js with more than 20k monthly downloads.

This package has a lot of unit tests with high test coverage for ensuring its correctness.

Key Features

  • Convert between Jalali, Gregorian and Flutter's DateTime objects.
  • Access year, month, day, weekday, Julian day number, month length and ... through getters.
  • Format Jalali and Georgian dates with an easy and powerful syntax using DateFormatter.
  • Ensure Jalali and Georgian dates validity.
  • Check if a Jalali or Gregorian year is leap.
  • Immutable date objects with copy methods for easy manipulation.
  • Compare Dates easily with comparison operators or by using Comparable.
  • Add or subtract days with + and - operators.
  • Find distance between dates by methods and ^ operator.
  • Add years, months and days separately or as a combination with methods.
  • High code coverage with a lot of unit tests.
  • Null-Safe API

Recent Changes

As of version 0.16.0 toUTCDateTime method is added and toDateTime has more functionality.

Issues and feature requests

If you want a new feature, or you found an issue, please make an issue on GitHub, so I can see your request.

Usage

Add it to your pubspec.yaml file:

dependencies:
    shamsi_date: ^latest.version

Then depend on it:

import 'package:shamsi_date/shamsi_date.dart';

If you want extension methods, also depend on extensions:

import 'package:shamsi_date/extensions.dart';

Jalali class is used for Shamsi (Jalali, Persian, شمسی or خورشیدی) date and Gregorian class is used for Gregorian (Miladi or میلادی) date. Jalali and Gregorian classes are the subclasses of Date.

Jalali and Gregorian can be instantiated with providing year, month and day among other ways:

Jalali j = Jalali(year, month, day);
Gregorian g = Gregorian(year, month, day);

Month and day has default value of 1 if you don't specify them, so Jalali(year, month) is equivalent to Jalali(year, month, 1) and Gregorian(year) is equivalent to Gregorian(year, 1, 1).

Constructor arguments should be non-null or exception will be thrown immediately. This ensures objects being in valid state when created. So year, month and day are always non-null. Almost all methods, operators, constructors and factories should have non-null arguments, and they will return non-null objects. For example year, month and day getters will return non-null results. The only exception for methods which can accept null arguments are methods with optional arguments like add(...) and copy(...). in nullsafe version: nullable and non-nullable argument and return types are checked statically.

All created date instances are valid. When creating a date instance either by using constructors and factories or by using methods and operators on an existing date instance, if the new date is invalid (by its month or day being out of range), or it is out of computable range, a DateException exception is thrown. So if you think the new date instance can become invalid or out of range you should surround it with try-catch and catching DateException. Minimum computable date is Gregorian(560,3,20) or equivalently Jalali(-61,1,1) and Maximum computable date is Gregorian(3798,12,31) or equivalently Jalali(3177,10,11). For example:

void main() {
  try {
    Jalali jv = Jalali(1398, 13, 1); // not valid!
  } on DateException catch (e) {
    // prints: DateException: Jalali month is out of valid range.
    print(e);
  }
}

Jalali and Gregorian objects are immutable. So using operators and methods will give you new object and does not manipulate the object in place, like String objects. Almost all other objects in shamsi_date library are immutable too.

You can access year, month, day through getters on Jalali or Gregorian dates. You can get week day number of Jalali and Gregorian by using weekDay getter. Week days range from 1 to 7. Jalali week starts with Shanbe and Gregorian week starts with Monday. Month length can be accessed using monthLength getter. Month length is sensitive to leap years. you can check if the year is a leap year by isLeapYear() method. Julian day number is also accessible through julianDayNumber getter. for example:

Jalali j = Jalali(1397, 5, 6);

int jy = j.year; // jy = 1397
int jm = j.month; // jm = 5
int jd = j.day; // jd = 6

int wd = j.weekDay; // wd = 1 (Shanbe)

// month length of 1397/5
// note: day value is not important for monthLength
int ml = j.monthLength; // ml = 31

// check if 1397 is a leap year
// note: month and day values are not important for isLeapYear() method
bool ly = j.isLeapYear(); // ly = false (1397 is not leap year)

// and equivalently for Gregorian date objects ...

You can convert Jalali dates to Gregorian by using toGregorian() method and convert Gregorian to Jalali date by using toJalali() method. There are also factory methods Jalali.fromGregorian(...) and Gregorian.fromJalali(...) which can be used alternatively.

Jalali j = Jalali(1397, 5, 6);
// convert to Gregorian:
Gregorian j2g1 = j.toGregorian(); // -> 2018/8/28
// or equivalently:
Gregorian j2g2 = Gregorian.fromJalali(j);

Gregorian g = Gregorian(2019, 10, 26);
// convert to Jalali:
Jalali g2j1 = g.toJalali(); // -> 1398/8/4
// or equivalently:
Jalali g2j2 = Jalali.fromGregorian(g);

You can convert DateTime objects directly to Jalali or Gregorian dates by using fromDateTime(dateTime) static methods. Convert Jalali and Gregorian to DateTime by using toDateTime() method. You can pass hour, minute and other time details to arguments. There is also toUTCDateTime for UTC date times. Get Jalali and Gregorian dates for now by using now() factory.

// convert from DateTime
Jalali j = Jalali.fromDateTime(dateTime);
Gregorian g = Gregorian.fromDateTime(dateTime);

// convert to DateTime
DateTime j2dt = j.toDateTime();
DateTime g2dt = g.toDateTime();

// you can also add hour, minute, ...
DateTime j2dt1 = j.toDateTime(13, 25, 48);
// and also convert to UTC:
DateTime j2dt2 = j.toUTCDateTime(13, 25, 48);

// get now
Jalali jNow = Jalali.now();
Gregorian gNow = Gregorian.now();

For converting DateTime you can also use extension methods.

DateTime dt = DateTime.now();
Jalali j = dt.toJalali();
Gregorian g = dt.toGregorian();

Jalali and Georgian dates are immutable, so you can not change their properties in place. if you want only to change some fields of a Jalali or Gregorian date you can use copy(...) method or withYear, withMonth and withDay methods on an existing object. These methods can be chained. copy method changes all fields at one. note that copy and with*() methods are not safe, and it is your responsibility to avoid problems like month length bound (for example changing month of 31 Farvardin 1390 to Esfand) or leap crash (for example being in last day of year in a leap year and changing year to a non-leap one) in intermediate steps. order of operations is important.

For example for getting date at start of this month in Jalali: (copy method makes another object instance and leaves the original one unchanged)

Jalali j1 = Jalali.now().withDay(1); // correct way
// or by using copy method:
Jalali j2 = Jalali.now().copy(day: 1); // also correct

// DON NOT do it like this:
Jalali j3 = Jalali(Jalali.now().year, Jalali.now().month, 1); // INCORRECT

Or if you want to get last day of the last month of this Jalali year:

// at first go to first day of last month: (Avoid leap crash)
Jalali tmp = Jalali.now().withDay(1).withMonth(12);
// since we can be in a leap year we use monthLength for going to last day:
Jalali j = tmp.withDay(tmp.monthLength);

// or by using copy method:
Jalali tmp1 = Jalali.now().copy(month: 12, day: 1);
Jalali j1 = tmp.copy(day: tmp1.monthLength);

or to find 3rd day of 2nd month of this year:

Jalali j = Jalali.now().withDay(3).withMonth(2);

// or by using copy method:
Jalali j1 = Jalali.now().copy(month: 2, day: 3);

Or If you want your Jalali and Gregorian objects to fall back to today if null is provided as their constructor arguments you can use copy method from now factory method, for example for Jalali:

Jalali j = Jalali.now().copy(year: y, month: m, day: d);
// y, m and d can be null

You can find distance between Jalali and Gregorian dates by using ^ operator. Note that - operator is for something else. Or you can use distanceTo and distanceFrom methods.

int distance11 = Jalali.now() ^ Jalali(1395, 10, 1);
// or
int distance12 = Jalali.now().distanceFrom(Jalali(1395, 10, 1));
// or
int distance13 = Jalali(1395, 10, 1).distanceTo(Jalali.now());

// and similarly for Gregorian
int distance2 = Gregorian(2021) ^ Gregorian(2020);

You can add and subtract days to Jalali and Gregorian using + and - operators. It is guaranteed to give you a bound valid date. for example, it will go to next month or next year if needed, and they won't have leap crash.

You can add years, months or days to Jalali and Gregorian using addYears, addMonths and addDays. These methods can be chained, and they will not have range crash. addDays can change month and year. addMonths can change year. note that it is your responsibility to avoid leap crash.

If you want you can add a combination of days, months or years to a date object with add method. note that add method is not safe and does not manipulate result to become bound valid, it is your responsibility. It is recommended to use addYear, addMonth and addDay methods over add method. note By using addYears, addMonth and addDay you can put day out of month length bounds. addMonth is safe for month overflow.

Jalali j1 = Jalali(1398, 8, 4);
// add days
Jalali j2 = j1 + 3; // -> 1398/8/7
// result will be manipulated to become valid:
Jalali j3 = j1 + 30; // -> 1398/9/4
Jalali j4 = j1 + 365; // -> 1399/8/4
// subtract days
Jalali j5 = j1 - 2; // -> 1398/8/2

// add years, months and days:
Jalali j6 = j1.addYears(1).addMonths(2).addDays(3); // 1399/10/7
// or:
Jalali j60 = j1.add(years: 1, months: 2, days: 3); // 1399/10/7
// add years and days only:
Jalali j7 = j1.addYears(1).addDays(3); // 1399/8/7
// or:
Jalali j70 = j1.add(years: 1, days: 3); // 1399/8/7
// add months only:
Jalali j8 = j1.addMonths(2); // 1398/10/3
// or:
Jalali j80 = j1.add(months: 2); // 1398/10/3
// if you want to subtract you can add negative value:
Jalali j9 = j1.addYears(-1); // 1397/8/3
// or:
Jalali j90 = j1.add(years: -1); // 1397/8/3

// addYears, addMonths and addDays methods are bound safe
// add(...) method is NOT bound safe

Date formatting is easy. You should make a function for custom formatting and then pass your Jalali or Gregorian dates to this function.

For example if you want to format as WeekDayName Day MonthName TwoDigitYear you make a function for it:

String format1(Date d) {
  final f = d.formatter;

  return '${f.wN} ${f.d} ${f.mN} ${f.yy}';
}

// example output for Jalali: "پنج شنبه 21 دی 91"
// example output for Gregorian: "Thursday 10 January 13"

Or if you want to format as FourDigitYear/TwoDigitMonth/TwoDigitDay or YYYY/MM/DD, you make a function for it:

String format2(Date d) {
  final f = d.formatter;

  return '${f.yyyy}/${f.mm}/${f.dd}';
}

Then use it like before.

Note that formatter formats digits in English so if you want Persian digits you can use fonts with Persian digits or apply a simple mapping to formatter output to change English digits to Persian.

Jalali and Georgian dates support toString() method. For Jalali, it is semantically equivalent to use a formatter as Jalali(Y,M,D) which means:

String toStringFormatter(Jalali d) {
  final f = d.formatter;

  return 'Jalali(${f.y},${f.m},${f.d})';
}

For Georgian, toString() is equivalent to using a formatter as Georgian(Y,M,D).

Note: in the following code toString() is called implicitly:

void main() {
    print(Jalali.now());
    final str = 'today is: ${Georgian.now()}';
}

Use toString() of Jalali and Georgian dates only for development purpose, like for debugging, logging or ... You should use formatters for showing dates on the UI.

Note also that you do not need for example to use int.parse() on formatter output of Jalali.now().formatter.m for accessing its month, simply use Jalali.now().month.

DateFormatter has these getters:

  • y: year (whatever length it has). year should be positive.
  • yy: two digit year. year should be between 1000 and 9999.
  • yyyy: four digit year. year should be between 0 and 9999.
  • m: month (whatever length it has).
  • mm: two-digit month.
  • mN: month name.
  • d: day (whatever length it has).
  • dd: two digit day.
  • wN: week day name.

You can get date formatter by using formatter getter on Jalali and Gregorian date objects. Simply cash this formatter in a Jalali value and then use string interpolation (as we have shown in examples) for making your desired output. This way of formatting is more powerful (and arguably easier) than using templates.

Jalali and Gregorian classes are Comparable so you can compare them using compareTo method. You can also use comparison operators to compare them. They also support equals and hashCode functions. So you can safely use Sets and Maps of Jalali and Gregorian dates.

Jalali j1 = Jalali(1397, 1, 1);
Jalali j2 = Jalali(1397, 2, 1);

bool b1 = j1 < j2; // b1 = true
bool b2 = j1 >= j2; // b2 = false
// using Comparable compareTo
bool b3 = j1.compareTo(j2) > 0; // b3 = false (means j1 > j2 is false)
bool b4 = j1.compareTo(j2) <= 0; // b4 = true (means j1 <= j2 is true)
bool b5 = j1 == j2; // b5 = false
bool b6 = j1 != j2; // b6 = true

Example

Here is a complete example. If you did not find what you are looking for, you can check test/shamsi_date_test.dart file which includes unit tests.

4 // 4 means "Thursday" // find month length print('Jalali 1390/12 month length? ' '${Jalali(1390, 12).monthLength}'); // -> 29 print('Gregorian 2000/2 month length? ' '${Gregorian(2000, 2).monthLength}'); // -> 29 // check leap year print('1390 Jalali is leap year? ' '${Jalali(1390).isLeapYear()}'); // -> false print('2000 Gregorian is leap year? ' '${Gregorian(2000).isLeapYear()}'); // -> true // validity: // ALL created instances are considered VALID // if you think a date might invalid, use try-catch: try { Jalali jv = Jalali(1398, 13, 1); // not valid! print(jv); // this line is not reached } on DateException catch (e) { // prints: DateException: Jalali month is out of valid range. print(e); } // making leap crash will also throw exception: // for ex: Jalali(1394, 12, 30) will crash, since // 1394 is not leap year // creating dates out of computable range also throws DateException. // convert DateTime object to Jalali and Gregorian DateTime dateTime = DateTime.now(); print('now is $dateTime'); print('now is ${Gregorian.fromDateTime(dateTime)} in Gregorian'); print('now is ${Jalali.fromDateTime(dateTime)} in Jalali'); // convert to DateTime print('$j1 is ${j1.toDateTime()}'); print('$g1 is ${g1.toDateTime()}'); // convert Jalali and Gregorian to DateTime print('$j1 as DateTime is ${j1.toDateTime()}'); print('$g1 as DateTime is ${g1.toDateTime()}'); // find today with now() factory method print('now is ${Gregorian.now()} in Gregorian'); print('now is ${Jalali.now()} in Jalali'); // find out which jalali year is this year: int thisJalaliYear = Jalali.now().year; print('this Jalali year is $thisJalaliYear'); // copy method print('$j1 with year = 1300 is ${j1.copy(year: 1300)}'); // prints: 1391/10/21 with year = 1300 is 1300/10/21 print('$g1 with month = 1 and day = 2 is ${g1.copy(month: 1, day: 2)}'); // prints: 2013/1/10 with month = 1 and day = 2 is 2013/1/2 // withYear, withMonth and withDay methods: // these methods can be chained // it is recommended to use these methods over copy method print('$j1 with year = 1300 is ${j1.withYear(1300)}'); // prints: 1391/10/21 with year = 1300 is 1300/10/21 print('$g1 with month = 1 and day = 2 is ${g1.withDay(2).withMonth(1)}'); // prints: 2013/1/10 with month = 1 and day = 2 is 2013/1/2 // for example for getting date at start of this month in Jalali: print(Jalali.now().copy(day: 1)); // for example to find 3rd day of 2nd month of this year: print(Jalali.now().copy(month: 2, day: 3)); // DON NOT do it like this: print(Jalali(Jalali.now().year, Jalali.now().month, 1)); // INCORRECT // for example if you want to get // the last day of the last month of this Jalali year: Jalali tmp = Jalali.now().copy(month: 12, day: 1); // since we can be in a leap year we use monthLength: print(tmp.copy(day: tmp.monthLength)); // add and subtract days Jalali d1 = Jalali(1398, 8, 4); // add days print(d1 + 3); // -> 1398/8/7 // result will be manipulated to become valid: print(d1 + 30); // -> 1398/9/4 print(d1 + 365); // -> 1399/8/4 // subtract days print(d1 - 2); // -> 1398/8/2 // add years, months and days: print(d1.add(years: 1, months: 2, days: 3)); // 1399/10/7 // add years and days only: print(d1.add(years: 1, days: 3)); // 1399/8/7 // add months only: print(d1.add(months: 2)); // 1398/10/3 // if you want to subtract you can add negative value: print(d1.add(years: -1)); // 1397/8/3 // and also for Gregorian // you can find distance between two days with "^" operator int distance11 = Jalali.now() ^ Jalali(1395, 10); int distance12 = Jalali.now().distanceFrom(Jalali(1395, 10)); int distance13 = Jalali(1395, 10).distanceTo(Jalali.now()); print('distance $distance11 $distance12 $distance13'); // and similarly for Gregorian // or you can use addYears, addMonths and addDays method // it is recommended to use these methods over add method // these methods are bound valid which means result will be // manipulated to become valid, but add method is not print(d1.addDays(30)); // -> 1398/9/4 print(d1.addDays(365)); // -> 1399/8/4 print(d1.addYears(1).addMonths(2).addDays(3)); // 1399/10/7 print(d1.addYears(1).addDays(3)); // 1399/8/7 print(d1.addMonths(2)); // 1398/10/3 print(d1.addYears(-1)); // 1397/8/3 // formatting examples: // example one: String format1(Date d) { final f = d.formatter; return '${f.wN} ${f.d} ${f.mN} ${f.yy}'; } print(format1(j1)); // prints: پنج شنبه 21 دی 91 print(format1(g1)); // prints: Thursday 10 January 13 // example one: String format2(Date d) { final f = d.formatter; return '${f.dd}/${f.mm}/${f.yyyy}'; } print(format2(j1)); // prints: 21/10/1391 print(format2(g1)); // prints: 10/01/2013 // DO NOT use formatter for accessing year, month or other properties // of date objects they are available as getters on date objects // INCORRECT EXAMPLE, DO NOT USE THIS: int j1y1 = int.parse(j1.formatter.yyyy); // INCORRECT print("j1's year is $j1y1"); // use this: int j1y2 = j1.year; // correct print("j1's year is $j1y2"); // also using toString() for showing dates on UI is not recommended, // use custom formatter. // comparing dates examples: print(j1 > j2); // -> false print(j1.compareTo(j2) > 0); // -> false print(j1 <= j2); // -> true print(j1.compareTo(j2) <= 0); // -> true print(g1 >= g2); // -> true print(g1.compareTo(g2)); // -> 0 print(g1 == g2); // -> true print(g1 != g1); // -> false // if you want to compare Jalali with Georgian // you can convert one type to another, // for example: print(j1.toGregorian() == g1); // -> true // but if you don't want to convert them you can use julianDayNumber // (this approach is not recommended) print(j1.julianDayNumber == g1.julianDayNumber); // -> true // this means that they are equal // you can also use other comparison operators // you can use extension methods for DateTime final dtn = DateTime.now(); print(dtn); final jn = dtn.toJalali(); print(jn); final gn = dtn.toGregorian(); print(gn); } ">
import 'package:shamsi_date/shamsi_date.dart';
import 'package:shamsi_date/extensions.dart';

void main() {
  // Gregorian to Jalali conversion
  Gregorian g1 = Gregorian(2013, 1, 10);
  Jalali j1 = g1.toJalali();
  print('$g1 == $j1');
  // prints: Gregorian(2013,1,10) == Jalali(1391,10,21)
  // you can write Jalali.fromGregorian(g1) instead of g1.toJalali()

  // access year, month and day through getters
  // for Jalali:
  int j1y = j1.year; // j1y = 1391
  int j1m = j1.month; // j1m = 10
  int j1d = j1.day; // j1d = 21
  print('j1 is $j1y-$j1m-$j1d'); // prints: j1 is 1397-10-21
  // NOTE: use formatters for formatting dates
  // and for Gregorian:
  int g1y = g1.year; // g1y = 2013
  int g1m = g1.month; // g1m = 1
  int g1d = g1.day; // g1d = 10
  print('g1 is $g1y-$g1m-$g1d'); // prints: g1 is 2013-1-10
  // NOTE: use formatters for formatting dates

  // Jalali to Gregorian conversion
  Jalali j2 = Jalali(1391, 10, 21);
  Gregorian g2 = j1.toGregorian();
  print('$j2 == $g2');
  // prints: Jalali(1391,10,21) == Gregorian(2013,1,10)
  // also can use Gregorian.fromJalali(j1) instead of j1.toGregorian()

  // find weekDay
  print('$j1 has weekDay ${j1.weekDay}'); // -> 6
  // 6 means "پنج شنیه"
  print('$g1 has weekDay ${g1.weekDay}'); // -> 4
  // 4 means "Thursday"

  // find month length
  print('Jalali 1390/12 month length? '
      '${Jalali(1390, 12).monthLength}'); // -> 29
  print('Gregorian 2000/2 month length? '
      '${Gregorian(2000, 2).monthLength}'); // -> 29

  // check leap year
  print('1390 Jalali is leap year? '
      '${Jalali(1390).isLeapYear()}'); // -> false
  print('2000 Gregorian is leap year? '
      '${Gregorian(2000).isLeapYear()}'); // -> true

  // validity:
  // ALL created instances are considered VALID
  // if you think a date might invalid, use try-catch:
  try {
    Jalali jv = Jalali(1398, 13, 1); // not valid!
    print(jv); // this line is not reached
  } on DateException catch (e) {
    // prints: DateException: Jalali month is out of valid range.
    print(e);
  }
  // making leap crash will also throw exception:
  // for ex: Jalali(1394, 12, 30) will crash, since
  //  1394 is not leap year
  // creating dates out of computable range also throws DateException.

  // convert DateTime object to Jalali and Gregorian
  DateTime dateTime = DateTime.now();
  print('now is $dateTime');
  print('now is ${Gregorian.fromDateTime(dateTime)} in Gregorian');
  print('now is ${Jalali.fromDateTime(dateTime)} in Jalali');
  // convert to DateTime
  print('$j1 is ${j1.toDateTime()}');
  print('$g1 is ${g1.toDateTime()}');

  // convert Jalali and Gregorian to DateTime
  print('$j1 as DateTime is ${j1.toDateTime()}');
  print('$g1 as DateTime is ${g1.toDateTime()}');

  // find today with now() factory method
  print('now is ${Gregorian.now()} in Gregorian');
  print('now is ${Jalali.now()} in Jalali');
  // find out which jalali year is this year:
  int thisJalaliYear = Jalali.now().year;
  print('this Jalali year is $thisJalaliYear');

  // copy method
  print('$j1 with year = 1300 is ${j1.copy(year: 1300)}');
  // prints: 1391/10/21 with year = 1300 is 1300/10/21
  print('$g1 with month = 1 and day = 2 is ${g1.copy(month: 1, day: 2)}');
  // prints: 2013/1/10 with month = 1 and day = 2 is 2013/1/2

  // withYear, withMonth and withDay methods:
  // these methods can be chained
  // it is recommended to use these methods over copy method
  print('$j1 with year = 1300 is ${j1.withYear(1300)}');
  // prints: 1391/10/21 with year = 1300 is 1300/10/21
  print('$g1 with month = 1 and day = 2 is ${g1.withDay(2).withMonth(1)}');
  // prints: 2013/1/10 with month = 1 and day = 2 is 2013/1/2

  // for example for getting date at start of this month in Jalali:
  print(Jalali.now().copy(day: 1));
  // for example to find 3rd day of 2nd month of this year:
  print(Jalali.now().copy(month: 2, day: 3));
  // DON NOT do it like this:
  print(Jalali(Jalali.now().year, Jalali.now().month, 1)); // INCORRECT
  // for example if you want to get
  // the last day of the last month of this Jalali year:
  Jalali tmp = Jalali.now().copy(month: 12, day: 1);
  // since we can be in a leap year we use monthLength:
  print(tmp.copy(day: tmp.monthLength));

  // add and subtract days
  Jalali d1 = Jalali(1398, 8, 4);
  // add days
  print(d1 + 3); // -> 1398/8/7
  // result will be manipulated to become valid:
  print(d1 + 30); // -> 1398/9/4
  print(d1 + 365); // -> 1399/8/4
  // subtract days
  print(d1 - 2); // -> 1398/8/2
  // add years, months and days:
  print(d1.add(years: 1, months: 2, days: 3)); // 1399/10/7
  // add years and days only:
  print(d1.add(years: 1, days: 3)); // 1399/8/7
  // add months only:
  print(d1.add(months: 2)); // 1398/10/3
  // if you want to subtract you can add negative value:
  print(d1.add(years: -1)); // 1397/8/3
  // and also for Gregorian

  // you can find distance between two days with "^" operator
  int distance11 = Jalali.now() ^ Jalali(1395, 10);
  int distance12 = Jalali.now().distanceFrom(Jalali(1395, 10));
  int distance13 = Jalali(1395, 10).distanceTo(Jalali.now());
  print('distance $distance11 $distance12 $distance13');
  // and similarly for Gregorian

  // or you can use addYears, addMonths and addDays method
  // it is recommended to use these methods over add method
  // these methods are bound valid which means result will be
  //  manipulated to become valid, but add method is not
  print(d1.addDays(30)); // -> 1398/9/4
  print(d1.addDays(365)); // -> 1399/8/4
  print(d1.addYears(1).addMonths(2).addDays(3)); // 1399/10/7
  print(d1.addYears(1).addDays(3)); // 1399/8/7
  print(d1.addMonths(2)); // 1398/10/3
  print(d1.addYears(-1)); // 1397/8/3

  // formatting examples:

  // example one:
  String format1(Date d) {
    final f = d.formatter;

    return '${f.wN} ${f.d} ${f.mN} ${f.yy}';
  }

  print(format1(j1)); // prints: پنج شنبه 21 دی 91
  print(format1(g1)); // prints: Thursday 10 January 13

  // example one:
  String format2(Date d) {
    final f = d.formatter;

    return '${f.dd}/${f.mm}/${f.yyyy}';
  }

  print(format2(j1)); // prints: 21/10/1391
  print(format2(g1)); // prints: 10/01/2013

  // DO NOT use formatter for accessing year, month or other properties
  // of date objects they are available as getters on date objects
  // INCORRECT EXAMPLE, DO NOT USE THIS:
  int j1y1 = int.parse(j1.formatter.yyyy); // INCORRECT
  print("j1's year is $j1y1");
  // use this:
  int j1y2 = j1.year; // correct
  print("j1's year is $j1y2");
  // also using toString() for showing dates on UI is not recommended,
  // use custom formatter.

  // comparing dates examples:
  print(j1 > j2); // -> false
  print(j1.compareTo(j2) > 0); // -> false
  print(j1 <= j2); // -> true
  print(j1.compareTo(j2) <= 0); // -> true
  print(g1 >= g2); // -> true
  print(g1.compareTo(g2)); // -> 0
  print(g1 == g2); // -> true
  print(g1 != g1); // -> false

  // if you want to compare Jalali with Georgian
  // you can convert one type to another,
  // for example:
  print(j1.toGregorian() == g1); // -> true
  // but if you don't want to convert them you can use julianDayNumber
  // (this approach is not recommended)
  print(j1.julianDayNumber == g1.julianDayNumber); // -> true
  // this means that they are equal
  // you can also use other comparison operators

  // you can use extension methods for DateTime
  final dtn = DateTime.now();
  print(dtn);
  final jn = dtn.toJalali();
  print(jn);
  final gn = dtn.toGregorian();
  print(gn);
}
Comments
  • Jalali day is out of valid range

    Jalali day is out of valid range

    Hi I have the same problem here The point is this is ONLY happening today at 1400/05/31 (8/2/2021) and was working fine the other days

    code where this is happening

    Jalali date;
    var initDate = '1400/05/31';
    var splitDate = initDate.split("/");
    var date1 = Jalali(int.parse(splitDate[0]), int.parse(splitDate[1]), int.parse(splitDate[2]));
    date = date1.addMonths(3);      -------------> The line that exception happens
    

    the Exception:

    E/flutter (29797): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: DateException: Jalali day is out of valid range.
    E/flutter (29797): #0      new Jalali (package:persian_datetime_picker/src/date/src/jalali/jalali_date.dart:160:9)
    E/flutter (29797): #1      Jalali.addMonths (package:persian_datetime_picker/src/date/src/jalali/jalali_date.dart:480:14)
    E/flutter (29797): #2      UtilFunctions.addMonth (package:kenaretam/util/util_functions.dart:218:13)
    E/flutter (29797): #3      _SubmitPropertyPageState._submitProperty (package:kenaretam/route/property/submit_property.dart:1514:25)
    E/flutter (29797): #4      _SubmitPropertyPageState._bottomNavigationBar.<anonymous closure> (package:kenaretam/route/property/submit_property.dart:406:21)
    E/flutter (29797): #5      _SubmitPropertyPageState._bottomNavigationBar.<anonymous closure> (package:kenaretam/route/property/submit_property.dart:404:30)
    E/flutter (29797): #6      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:991:20)
    E/flutter (29797): #7      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
    E/flutter (29797): #8      TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:607:11)
    E/flutter (29797): #9      BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:296:5)
    E/flutter (29797): #10     BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:230:7)
    E/flutter (29797): #11     PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:475:9)
    E/flutter (29797): #12     PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:93:12)
    E/flutter (29797): #13     PointerRouter._dispatchEventToRoutes.<anonymous closure> (package:flutter/src/gestures/pointer_router.dart:138:9)
    E/flutter (29797): #14     _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:397:8)
    E/flutter (29797): #15     PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:136:18)
    E/flutter (29797): #16     PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:122:7)
    E/flutter (29797): #17     GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:381:19)
    E/flutter (29797): #18     GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:361:22)
    E/flutter (29797): #19     RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:278:11)
    E/flutter (29797): #20     GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:316:7)
    E/flutter (29797): #21     GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:280:5)
    E/flutter (29797): #22     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:238:7)
    E/flutter (29797): #23     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:221:7)
    E/flutter (29797): #24     _rootRunUnary (dart:async/zone.dart:1370:13)
    E/flutter (29797): #25     _CustomZone.runUnary (dart:async/zone.dart:1265:19)
    E/flutter (29797): #26     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1170:7)
    E/flutter (29797): #27     _invoke1 (dart:ui/hooks.dart:180:10)
    E/flutter (29797): #28     PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:276:7)
    E/flutter (29797): #29     _dispatchPointerDataPacket (dart:ui/hooks.dart:96:31)
    E/flutter (29797): 
    

    Even by changing the date (e.g. 1400/05/31 -> 1400/05/20 Or even 1400/04/20), the Exception still occurs

    question 
    opened by AliEasy 9
  • Jalali day is out of valid range.

    Jalali day is out of valid range.

    Hi, I am trying to get session by this command: Jalali.now().copy(month: 12).formatter.mN

    But I got This error :

     Jalali.now().copy(month: 12).formatter.mN
    Unhandled exception:
    DateException: Jalali day is out of valid range.
    #0      new Jalali (package:shamsi_date/src/jalali/jalali_date.dart:129:9)
    #1      Jalali.copy (package:shamsi_date/src/jalali/jalali_date.dart:222:14)
    #2      MonthPickerModel.Eval ()
    #3  
    

    I expect that I get اسفند .

    I am using shamsi_date: ^0.9.1 version and this is my doctor:

    Doctor summary (to see all details, run flutter doctor -v):
    [✓] Flutter (Channel stable, 2.0.5, on Linux, locale en_US.UTF-8)
    [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    [✓] Chrome - develop for the web
    [!] Android Studio (not installed)
    [✓] VS Code (version 1.56.2)
    [✓] Connected device (2 available)
    
    ! Doctor found issues in 1 category.
    
    question 
    opened by tazik561 7
  • The method distanceTo isn't defined for type Jalali

    The method distanceTo isn't defined for type Jalali

    I have this jalali instance :

        jStartDate = jStartDate.withDay(1);
        jEndDate = jEndDate.withDay(1);
    

    I want to find out how many days are between jStartDate and jEndDate ? So in order to find out days I am using : int distance = jStartDate.distanceTo(jEndDate);

    But I got: 'The method distanceTo isn't defined for type 'Jalali`

    question 
    opened by tazik561 6
  • FIXED compareTo bugs about time data

    FIXED compareTo bugs about time data

    The compareTo method returns +1 only if all parts (ANDs) of this date are greater than or equal other date. Consider the following two different times:

    1. 1400/01/01 10:10:10.999
    2. 1400/01/01 11:09:10.999

    The second one is greater than the first because of its hour but its minute is less than the first. I fixed the bug and added the relevant tests.

    bug 
    opened by Pourqavam 5
  • bug in addMonths method

    bug in addMonths method

    https://github.com/FatulM/shamsi_date/blob/218ef76c2dd4e41e6af0c7d80224c095f48d1050/lib/src/jalali/jalali_date.dart#L258

    این متد روز رو تغییر نمیده ، و مثلا اگر 31 شهریور باشیم میره به 31 مهر و خطا میخوره . ممنون میشم بررسی کنید

    question 
    opened by faridfr 5
  • Convert To Jalali directly from '2021-02-10T17:42:01'

    Convert To Jalali directly from '2021-02-10T17:42:01'

    Hi To get Gregorian from DateTime I have to use DateTime date = DateTime.parse(dateString); first and then use Jalali.fromDateTime(dateTime);

    It will be easier to have a shortcut for that.

    enhancement 
    opened by AliEasy 5
  • addMonth() make invalid date in some cases

    addMonth() make invalid date in some cases

    addMonth() method just go to the next month on same day but in some cases there are no such a date, like next month of 31/6 which is 31/7 or previous month of 31/1 which is 31/12

    enhancement 
    opened by NaarGes 5
  • Jalali day is out of range

    Jalali day is out of range

    Hello and thanks for the great work... there is a problem with the package... there are months in the gregorian calendar that are 29 days and those months are 30 days or 31 in Shamsi calendar... in this kind of months, the calendar would not work because ml => month length would be less than days of months.

    invalid 
    opened by ardeshir-33033 2
  • Diff 2 dates

    Diff 2 dates

    Suppose I have 2 Jalali instances, how do I diff them in months? I suppose converting them back to DateTime and using difference method won't work, because there's no correlation between Jalali and Gregorian month diffs.

    question 
    opened by mehrdad-shokri 1
  • copy(), withDay(), ... not exist

    copy(), withDay(), ... not exist

    hello I want to use copy(...) method or withYear, withMonth and withDay methods on an existing object but these methods don't exist in Jalaali objects.

    question 
    opened by NaarGes 1
  • Month checking Issue

    Month checking Issue

    There was an error in Jalali formatter file which was an if statement checking if received month is treater than ml or not(ml being month length). months are 31 or 30 but it just accepted lower than this number meaning greatest month length was 30 so I got an error and check you code and found it out. I committed my change so it would be great if you accepted it ASAP because Im using it inside my project. Thanks in advance :)

    bug invalid 
    opened by Mohammad-Hosein88 3
Releases(v1.0.1)
Owner
Amirreza Madani
Android and Flutter Developer.
Amirreza Madani
Calendar widget for flutter that is swipeable horizontally. This widget can help you build your own calendar widget highly customizable.

flutter_calendar_carousel Calendar widget for flutter that is swipeable horizontally. This widget can help you build your own calendar widget highly c

dooboolab 750 Jan 7, 2023
A Flutter package allows you to easily implement all calendar UI and calendar event functionality. 👌🔝🎉

calendar_view A Flutter package allows you to easily implement all calendar UI and calendar event functionality. For web demo visit Calendar View Exam

Simform Solutions 219 Dec 22, 2022
A Dart package to help you with managing dates easily.

?? Dateable A Dart package to help you with managing dates easily. Can be used to store, format, convert, construct, parse and serialise dates. Calend

Jakub Krąpiec 6 Dec 2, 2021
Flutter calendar app. register schedule and manage in calendar ui.

flutter calendar app. register schedule and manage in calendar ui. save schedule data in firestore. and create widget and read schedule from firestore in widget.

akiho 11 Oct 30, 2022
Highly customizable, feature-packed calendar works like google calendar but with more features.

Beca [In Progress] Beca is a Calendar that you could manage your daily tasks and schedule meetings with your friends just like google calendar Concept

Mohammad Javad Hossieni 19 Nov 15, 2022
Flutter calendar week UI package

Flutter calendar week Flutter calendar week UI package IOS | Android: import 'package:flutter_calendar_week/flutter_calendar_week.dart'; CalendarWeek(

null 67 Dec 12, 2022
A seasonal foods calendar app written in Dart using Flutter.

This project is not actively maintained anymore. However, everybody who wants to do so is more than welcome to work on this project! Thank you for you

Andreas Boltres 63 Nov 19, 2022
Easy to use and beautiful calendar strip component for Flutter.

Flutter Calendar Strip Easy to use and beautiful calendar strip component for Flutter. Awesome celender widget If this project has helped you out, ple

Siddharth V 176 Dec 14, 2022
CalendarDatePicker2 - A lightweight and customizable calendar picker based on Flutter CalendarDatePicker

A lightweight and customizable calendar picker based on Flutter CalendarDatePicker, with support for single date picker, range picker and multi picker.

Neo Liu 27 Dec 22, 2022
Fluboard - Calendar wall-board-display built with Flutter and ❤️

Fluboard Calendar wall-board-display built with Flutter and ❤️ Goals Build calendar board (DAKBoard alternative) which easy to install and easy to cus

iTeqno 10 Dec 27, 2022
Calendar widget for flutter

Calendar Shows a scrolling calendar list of events. This is still relatively basic, it always assumes that the getEvents returns the entire list of ca

null 223 Dec 19, 2022
Highly customizable, feature-packed calendar widget for Flutter

Table Calendar Highly customizable, feature-packed Flutter Calendar with gestures, animations and multiple formats. Table Calendar with custom styles

Aleksander Woźniak 1.5k Jan 7, 2023
Flutter Date Picker Library that provides a calendar as a horizontal timeline.

DatePickerTimeline Flutter Date Picker Library that provides a calendar as a horizontal timeline. How To Use Import the following package in your dart

LiLi 0 Oct 25, 2021
Flutter Date Picker Library that provides a calendar as a horizontal timeline

Flutter Date Picker Library that provides a calendar as a horizontal timeline.

Vivek Kaushik 214 Jan 7, 2023
Calendar widget library for Flutter apps.

Calendarro Calendar widget library for Flutter apps. Offers multiple ways to customize the widget. Getting Started Installation Add dependency to your

Adam Styrc 97 Nov 30, 2022
Flutter Inline Calendar

inline_calendar An inline calendar flutter package inspired by outlook app. It also supports Jalali/Shamsi calendar. Uses theme and locale of context

omid habibi 3 Oct 21, 2022
A calendar widget for Flutter.

flutter_calendar A calendar widget for Flutter Apps. Borrowed DateTime utility functions from the Tzolkin Calendar web element. Usage Add to your pubs

AppTree Software, Inc 336 Sep 6, 2022
Collection of customisable calendar related widgets for Flutter.

calendar_views Collection of customisable calendar related widgets for Flutter. Day View Day View Documentation Set of widgets for displaying a day vi

Zen Lednik 99 Sep 8, 2022
A calendar widget to easily scroll through the years 🗓

Flutter Scrolling Calendar A customizable calendar widget to easily scroll through the years. Features Choose range of years and the initial year to s

Menno Renkens 113 Nov 19, 2022