A Flutter package for using Jalali (Shamsi, Solar, Persian, شمسی or خورشیدی) date. You can convert, format and manipulate Jalali and Georgian dates.
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:
Then depend on it:
If you want extension methods, also depend on extensions:
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:
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:
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:
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.
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.
For converting DateTime you can also use extension methods.
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)
Or if you want to get last day of the last month of this Jalali year:
or to find 3rd day of 2nd month of this year:
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:
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.
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.
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:
Or if you want to format as FourDigitYear/TwoDigitMonth/TwoDigitDay
or YYYY/MM/DD
, you make a function for it:
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:
For Georgian, toString() is equivalent to using a formatter as Georgian(Y,M,D)
.
Note: in the following code toString() is called implicitly:
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.
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.