diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..11ed588
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,3 @@
+
+issuehunt: morilog
+
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..fb8a116
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,35 @@
+name: tests
+
+on:
+  push:
+  pull_request:
+
+jobs:
+  tests:
+    runs-on: ubuntu-22.04
+
+    strategy:
+      fail-fast: true
+      matrix:
+        php: [ 7.1, 7.2, 7.3, 7.4, 8.0, 8.1, 8.2, 8.3 ]
+
+    name: PHP ${{ matrix.php }}
+
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v4
+
+      - name: Setup PHP
+        uses: shivammathur/setup-php@v2
+        with:
+          php-version: ${{ matrix.php }}
+          ini-values: error_reporting=E_ALL
+          tools: composer:v2
+          coverage: none
+
+      - name: Install dependencies
+        run: |
+          composer update --prefer-dist --no-interaction --no-progress
+
+      - name: Execute tests
+        run: vendor/bin/phpunit
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 2c1fc0c..28c68e4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
 /vendor
 composer.phar
 composer.lock
-.DS_Store
\ No newline at end of file
+.DS_Store
+.idea
+.phpunit.*
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 0a1c1cb..c75476e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,12 +1,13 @@
 language: php
 
-php: 
-  - 5.3
-  - 5.4
-  - 5.5
-
+php:
+  - 7.0
+  - 7.1
+  - 7.2
+  - 7.3
+  - 7.4
 before_script:
   - curl -s http://getcomposer.org/installer | php
   - php composer.phar install --dev
 
-script: phpunit
\ No newline at end of file
+script: ./vendor/bin/phpunit
diff --git a/Facades/JDateTime.php b/Facades/JDateTime.php
deleted file mode 100644
index 12616a2..0000000
--- a/Facades/JDateTime.php
+++ /dev/null
@@ -1,14 +0,0 @@
-
-## Installation
+- CalendarUtils class was ported from [jalaali/jalaali-js](https://github.com/jalaali/jalaali-js)
 
-In the `require` key of `composer.json` file add the following
+## Version 3 features
+- High human readable API
+- DateTime manipulating API
+- DateTime comparing API
+- Immutable
 
-```yml
-    "miladr/jalali": "dev-master"
+## Installation Version 3.*
+> If you are using version <= 2.*, please read [old docs](https://github.com/morilog/jalali/blob/v2.3.0/README.md)
+#### Requirements:
+- `php >= 7.0`
+
+Run the Composer update command
+
+    $ composer require morilog/jalali:3.*
+
+
+## Basic Usage
+In the current version, I introduced `Jalalian` class for manipulating Jalali date time
+### Jalalian
+In version >= 1.1,  you can use `jdate()` instead of `Jalalian::forge()`;
+#### `now([$timestamp = null])`
+``` php
+// the default timestamp is Now
+$date = \Morilog\Jalali\Jalalian::now()
+// OR
+$date = jdate();
+
+// pass timestamps
+$date = Jalalian::forge(1333857600);
+// OR
+$date = jdate(1333857600);
+
+// pass human readable strings to make timestamps
+$date = Jalalian::forge('last sunday');
+
+// get the timestamp
+$date = Jalalian::forge('last sunday')->getTimestamp(); // 1333857600
+
+// format the timestamp
+$date = Jalalian::forge('last sunday')->format('%B %d، %Y'); // دی 02، 1391
+$date = Jalalian::forge('today')->format('%A, %d %B %y'); // جمعه، 23 اسفند 97
+
+// get a predefined format
+$date = Jalalian::forge('last sunday')->format('datetime'); // 1391-10-02 00:00:00
+$date = Jalalian::forge('last sunday')->format('date'); // 1391-10-02
+$date = Jalalian::forge('last sunday')->format('time'); // 00:00:00
+
+// get relative 'ago' format
+$date = Jalalian::forge('now - 10 minutes')->ago() // 10 دقیقه پیش
 ```
 
-Run the Composer update comand
+#### Methods api
+---
 
-    $ composer update
 
-In your `config/app.php` add `'Miladr\Jalali\JalaliServiceProvider'` to the end of the `$providers` array
+```php
+public static function now(\DateTimeZone $timeZone = null): Jalalian
 
+$jDate = Jalalian::now();
+```
+
+---
 ```php
-    'providers' => array(
+public static function fromCarbon(Carbon $carbon): Jalalian
 
-        'Illuminate\Foundation\Providers\ArtisanServiceProvider',
-        'Illuminate\Auth\AuthServiceProvider',
-        ...
-        'Miladr\Jalali\JalaliServiceProvider',
+$jDate = Jalalian::fromCarbon(Carbon::now());
+```
 
-    ),
+---
+```php
+public static function fromFormat(string $format, string $timestamp, \DateTimeZone$timeZone = null): Jalalian 
+
+$jDate = Jalalian::fromFormat('Y-m-d H:i:s', '1397-01-18 12:00:40');
 ```
 
-
-## Basic Usage
-## Examples ##
 
-Some Examples (based on examples provided by Sallar)
+---
+```php
+public static function forge($timestamp, \DateTimeZone $timeZone = null): Jalalian
+
+// Alias fo fromDatetime
+```
 
+---
 ```php
-// default timestamp is now
-$date = jDate::forge();
+public static function fromDateTime($dateTime, \DateTimeZone $timeZone = null): Jalalian
 
-// pass timestamps
-$date = jDate::forge(1333857600);
+$jDate = Jalalian::fromDateTime(Carbon::now())
+// OR 
+$jDate = Jalalian::fromDateTime(new \DateTime());
+// OR
+$jDate = Jalalian::fromDateTime('yesterday');
 
-// pass strings to make timestamps
-$date = jDate::forge('last sunday');
+```
 
-// get the timestamp
-$date = jDate::forge('last sunday')->time(); // 1333857600
 
-// format the timestamp
-$date = jDate::forge('last sunday')->format('%B %d، %Y'); // دی 02، 1391
+---
+```php
+public function getMonthDays(): int
 
-// get a predefined format
-$date = jDate::forge('last sunday')->format('datetime'); // 1391-10-02 00:00:00
-$date = jDate::forge('last sunday')->format('date'); // 1391-10-02
-$date = jDate::forge('last sunday')->format('time'); // 00:00:00
+$date = (new Jalalian(1397, 1, 18))->getMonthDays() 
+// output: 31
+```
 
-// amend the timestamp value, relative to existing value
-$date = jDate::forge('2012-10-12')->reforge('+ 3 days')->format('date'); // 1391-07-24
+---
+```php
+public function getMonth(): int
 
-// get relative 'ago' format
-$date = jDate::forge('now - 10 minutes')->ago() // ۱۰ دقیقه پیش
+$date = (new Jalalian(1397, 1, 18))->getMonth() 
+// output: 1
+```
+
+---
+```php
+public function isLeapYear(): bool
+
+$date = (new Jalalian(1397, 1, 18))->isLeapYear() 
+// output: false
+
+```
+
+---
+```php
+public function getYear(): int
+
+$date = (new Jalalian(1397, 1, 18))->getYear() 
+// output: 1397
 ```
 
+---
+```php
+public function subMonths(int $months = 1): Jalalian
+
+$date = (new Jalalian(1397, 1, 18))->subMonths(1)->toString() 
+// output: 1396-12-18 00:00:00
+
+```
+
+---
+```php
+public function subYears(int $years = 1): Jalalian
+
+$date = (new Jalalian(1397, 1, 18))->subYears(1)->toString()
+// output: 1396-01-18 00:00:00
+```
+
+---
+```php
+public function getDay(): int
+
+$date = (new Jalalian(1397, 1, 18))->getDay() 
+// output: 18
+
+```
+
+---
+```php
+public function getHour(): int
+
+$date = (new Jalalian(1397, 1, 18, 12, 0, 0))->getHour() 
+// output: 12
+
+
+```
+
+---
+```php
+public function getMinute(): int
+
+$date = (new Jalalian(1397, 1, 18, 12, 10, 0))->getMinute() 
+// output: 10
+
+```
+
+---
+```php
+public function getSecond(): int
+
+$date = (new Jalalian(1397, 1, 18, 12, 10, 45))->getSecond() 
+// output: 45
+```
+
+---
+```php
+public function getTimezone(): \DateTimeZone
+
+// Get current timezone
+```
+
+---
+```php
+public function addMonths(int $months = 1): Jalalian
+
+$date = (new Jalalian(1397, 1, 18, 12, 10, 0))->addMonths(1)->format('m') 
+// output: 02
+
+```
+
+---
+```php
+public function addYears(int $years = 1): Jalalian
+
+$date = (new Jalalian(1397, 1, 18, 12, 10, 0))->addYears(1)->format('Y') 
+// output: 1398
+
+```
+
+---
+```php
+public function getDaysOf(int $monthNumber = 1): int
+
+$date = (new Jalalian(1397, 1, 18, 12, 10, 0))->getDaysOf(1) 
+// output: 31
+```
+
+---
+```php
+public function addDays(int $days = 1): Jalalian
+
+$date = (new Jalalian(1397, 1, 18, 12, 10, 0))->addDays(1)->format('d') 
+// output: 18
+
+```
+
+---
+```php
+public function toCarbon(): Carbon
+
+$date = (new Jalalian(1397, 1, 18, 12, 10, 0))->toCarbon()->toDateTimeString() 
+// output: 2018-04-07 12:10:00
+```
+
+---
+```php
+public function subDays(int $days = 1): Jalalian
+
+$date = (new Jalalian(1397, 1, 18, 12, 10, 0))->subDays(10)->format('d') 
+// output: 08
+```
+
+---
+```php
+public function addHours(int $hours = 1): Jalalian
+
+$date = (new Jalalian(1397, 1, 18, 12, 10, 0))->addHours(1)->format('H') 
+// output: 13
+
+```
+
+---
+```php
+public function subHours(int $hours = 1): Jalalian
+
+$date = (new Jalalian(1397, 1, 18, 12, 10, 0))->subHours(1)->format('H') 
+// output: 11
+
+```
+
+---
+```php
+public function addMinutes(int $minutes = 1): Jalalian
+
+$date = (new Jalalian(1397, 1, 18, 12, 10, 0))->addMinutes(10)->format('i') 
+// output: 22
+
+```
+
+---
+```php
+public function subMinutes(int $minutes = 1): Jalalian
+
+$date = (new Jalalian(1397, 1, 18, 12, 10, 0))->subMinutes(10)->format('i') 
+// output: 02
+
+```
+
+---
+```php
+public function addSeconds(int $secs = 1): Jalalian
+
+$date = (new Jalalian(1397, 1, 18, 12, 10, 0))->addSeconds(10)->format('s') 
+// output: 10
+
+```
+
+---
+```php
+public function subSeconds(int $secs = 1): Jalalian
+
+$date = (new Jalalian(1397, 1, 18, 12, 10, 0))->subSeconds(10)->format('i:s') 
+// output: 11:40
+
+
+```
+
+---
+```php
+public function equalsTo(Jalalian $other): bool
+
+$date = (new Jalalian(1397, 1, 18, 12, 10, 0))->equalsTo(Jalalian::now()) 
+// output: false
+
+$date = Jalalian::now()->equalsTo(Jalalian::now()) 
+// output: true
+
+```
+
+---
+```php
+public function equalsToCarbon(Carbon $carbon): bool
+
+$date = Jalalian::now()->equalsToCarbon(Carbon::now())  
+// output: true
+```
+
+---
+```php
+public function greaterThan(Jalalian $other): bool
+
+$date = Jalalian::now()->greaterThan(Jalalian::now()->subDays(1)))  
+// output: true
+```
+
+---
+```php
+public function greaterThanCarbon(Carbon $carbon): bool
+
+$date = Jalalian::now()->greaterThanCarbon(Carbon::now()->subDays(1)))  
+// output: true
+
+```
+
+---
+```php
+public function lessThan(Jalalian $other): bool
+
+$date = Jalalian::now()->lessThan(Jalalian::now()->addDays(1)))  
+// output: true
+
+```
+
+---
+```php
+public function lessThanCarbon(Carbon $carbon): bool
+
+$date = Jalalian::now()->lessThanCarbon(Carbon::now()->addDays(1)))  
+// output: true
+
+```
+
+---
+```php
+public function greaterThanOrEqualsTo(Jalalian $other): bool
+
+$date = Jalalian::now()->greaterThan(Jalalian::now()->subDays(1)))  
+// output: true
+
+```
+
+---
+```php
+public function greaterThanOrEqualsToCarbon(Carbon $carbon): bool
+
+$date = Jalalian::now()->greaterThanOrEqualsToCarbon(Carbon::now()))  
+// output: true
+
+```
+
+---
+```php
+public function lessThanOrEqualsTo(Jalalian $other): bool
+
+$date = Jalalian::now()->lessThanOrEqualsTo(Jalalian::now()))  
+// output: true
+
+```
+
+---
+```php
+public function lessThanOrEqualsToCarbon(Carbon $carbon): bool
+
+$date = Jalalian::now()->lessThanOrEqualsToCarbon(Carbon::now()))  
+// output: true
+
+```
+
+---
+```php
+public function isStartOfWeek(): bool
+
+$date = (new Jalalian(1397, 6, 24))->isStartOfWeek()
+// output: true
+
+```
+---
+```php
+public function getEndDayOfYear(): bool
+
+$date = (new Jalalian(1397, 6, 24))->getEndDayOfYear()
+// output: 1397, 12, 29
+
+```
+---
+```php
+public function getFirstDayOfMonth(): bool
+
+$date = (new Jalalian(1397, 6, 24))->getEndDayOfYear()
+// output: 1397, 6, 1
+
+```
+---
+```php
+public function getEndDayOfMonth(): bool
+
+$date = (new Jalalian(1397, 6, 24))->getEndDayOfMonth()
+// output: 1397, 6, 31
+
+```
+---
+```php
+public function isSaturday(): bool
+
+$date = (new Jalalian(1397, 6, 24))->isSaturday()
+// output: true
+
+```
+
+---
+```php
+public function isDayOfWeek(int $day): bool
+
+$date = (new Jalalian(1397, 6, 24))->isDayOfWeek(0)
+// output: true
+
+```
+
+---
+```php
+public function isEndOfWeek(): bool
+
+$date = (new Jalalian(1397, 6, 24))->isEndOfWeek()
+// output: false
+
+```
+
+---
+```php
+public function isFriday(): bool
+
+$date = (new Jalalian(1397, 6, 24))->isFriday()
+// output: false
+
+```
+
+---
+```php
+public function isToday(): bool
+
+$date = (new Jalalian(1397, 6, 24))->isToday()
+// output: (!maybe) true
+
+```
+
+---
+```php
+public function isTomorrow(): bool
+
+$date = (new Jalalian(1397, 6, 25))->isTomorrow()
+// output: true
+
+```
+
+---
+```php
+public function isYesterday(): bool
+
+$date = (new Jalalian(1397, 6, 23))->isYesterday()
+// output: true
+
+```
+
+---
+```php
+public function isFuture(): bool
+
+$date = (new Jalalian(1397, 6, 26))->isFuture()
+// output: true
+
+```
+
+---
+```php
+public function isPast(): bool
+
+$date = (new Jalalian(1397, 5, 24))->isPast()
+// output: true
+
+```
+
+---
+```php
+public function toArray(): array
+$date = (new Jalalian(1397, 6, 24))->toArray()
+// output: (
+//     [year] => 1397
+//     [month] => 6
+//     [day] => 24
+//     [dayOfWeek] => 0
+//     [dayOfYear] => 179
+//     [hour] => 0
+//     [minute] => 0
+//     [second] => 0
+//     [micro] => 0
+//     [timestamp] => 1536969600
+//     [formatted] => 1397-06-24 00:00:00
+//     [timezone] =>
+// )
+```
+
+---
+```php
+public function getDayOfWeek(): int
+
+$date = (new Jalalian(1397, 5, 24))->getDayOfWeek()
+// output: 0
+
+```
+
+---
+```php
+public function isSunday(): bool
+
+$date = (new Jalalian(1397, 6, 24))->isSunday()
+// output: false
+
+```
+
+---
+```php
+public function isMonday(): bool
+
+$date = (new Jalalian(1397, 6, 26))->isMonday()
+// output: true
+
+```
+
+---
+```php
+public function isTuesday(): bool
+
+$date = (new Jalalian(1397, 6, 24))->isTuesday()
+// output: false
+
+```
+
+---
+```php
+public function isWednesday(): bool
+
+$date = (new Jalalian(1397, 6, 24))->isWednesday()
+// output: false
+
+```
+
+---
+```php
+public function isThursday(): bool
+
+$date = (new Jalalian(1397, 6, 22))->isThursday()
+// output: true
+
+```
+
+---
+```php
+public function getDayOfYear(): int
+
+$date = (new Jalalian(1397, 5, 24))->getDayOfYear()
+// output: 179
+
+```
+
+---
+```php
+public function toString(): string
+$date = (new Jalalian(1397, 5, 24))->toString()
+// output: 1397-05-24 00:00:00
+
+```
+
+---
+```php
+public function format(string $format): string
+
+$date = (new Jalalian(1397, 5, 24))->format('y')
+// output: 1397
+// see php date formats
+
+```
+
+---
+```php
+public function __toString(): string
+
+// Alias of toString()
+```
+
+---
+```php
+public function ago(): string
+
+```
+
+---
+```php
+public function getTimestamp(): int
+
+```
+
+---
+```php
+public function getNextWeek(): Jalalian
+
+```
+
+---
+```php
+public function getNextMonth(): Jalalian
+
+```
+
+---
+```php
+public function diff(Jalalian $ref): array
+$diff = (new Jalalian(1397, 5, 24))->diff(new Jalalian(1398, 6, 30));
+// output: [1, 1, 6]
+
+```
+---
+```php
+public function next(string $dayName):Jalalian
+$next = (new Jalalian(1403, 5, 22))->next('شنبه')->format('Y-m-d');
+// output: 1403-05-27
+
+```
+---
+```php
+public function previous(string $dayName):Jalalian
+$previous = (new Jalalian(1403, 5, 22))->previous('شنبه')->format('Y-m-d');
+// output: 1403-05-20
+
+```
+### CalendarUtils
+---
+
+
+#### `checkDate($year, $month, $day, [$isJalali = true])`
+```php
+// Check jalali date
+\Morilog\Jalali\CalendarUtils::checkDate(1391, 2, 30, true); // true
+
+// Check jalali date
+\Morilog\Jalali\CalendarUtils::checkDate(2016, 5, 7); // false
+
+// Check gregorian date
+\Morilog\Jalali\CalendarUtils::checkDate(2016, 5, 7, false); // true
+```
+---
+#### `toJalali($gYear, $gMonth, $gDay)`
+```php
+\Morilog\Jalali\CalendarUtils::toJalali(2016, 5, 7); // [1395, 2, 18]
+```
+---
+#### `toGregorian($jYear, $jMonth, $jDay)`
+```php
+\Morilog\Jalali\CalendarUtils::toGregorian(1395, 2, 18); // [2016, 5, 7]
+```
+---
+#### `strftime($format, [$timestamp = false, $timezone = null])`
+```php
+CalendarUtils::strftime('Y-m-d', strtotime('2016-05-8')); // 1395-02-19
+```
+---
+#### `createDateTimeFromFormat($format, $jalaiTimeString)`
+```php
+$Jalalian = '1394/11/25 15:00:00';
+
+// get instance of \DateTime
+$dateTime = \Morilog\Jalali\CalendarUtils::createDatetimeFromFormat('Y/m/d H:i:s', $Jalalian);
+
+```
+---
+#### `createCarbonFromFormat($format, $jalaiTimeString)`
+```php
+$Jalalian = '1394/11/25 15:00:00';
+
+// get instance of \Carbon\Carbon
+$carbon = \Morilog\Jalali\CalendarUtils::createCarbonFromFormat('Y/m/d H:i:s', $Jalalian);
+
+```
+---
+#### `convertNumbers($string)`
+```php
+// convert latin to persian
+$date = \Morilog\Jalali\CalendarUtils::strftime('Y-m-d', strtotime('2016-05-8')); // 1395-02-19
+\Morilog\Jalali\CalendarUtils::convertNumbers($date); // ۱۳۹۵-۰۲-۱۹
+
+// convert persian to latin
+$dateString = \Morilog\Jalali\CalendarUtils::convertNumbers('۱۳۹۵-۰۲-۱۹', true); // 1395-02-19
+\Morilog\Jalali\CalendarUtils::createCarbonFromFormat('Y-m-d', $dateString)->format('Y-m-d'); //2016-05-8
+```
+
+---
+#### `Carbon api-difference`
+
+You can convert date/time to [briannesbitt/carbon](https://github.com/briannesbitt/carbon), thus being able to use it's [API](https://carbon.nesbot.com/docs/) to work with PHP DateTime class. 
+
+##### [Difference](https://carbon.nesbot.com/docs/#api-difference) in months:
+
+```php
+// convert persian to Carbon
+$date = \Morilog\Jalali\Jalalian::fromFormat('Y-m-d', "1395-02-19")->toCarbon(); 
+// ->toString() => Sun May 08 2016 00:00:00 GMT+0000
+
+// Add 4 months to Carbon
+$dateAdd4Months = $date->addMonths(4);
+
+// Difference in months
+$dateAdd4Months->DiffInMonths($date); //4
+$dateAdd4Months->floatDiffInMonths($date); //4.0
+```
 
+---
 ## Formatting ##
 
 For help in building your formats, checkout the [PHP strftime() docs](http://php.net/manual/en/function.strftime.php).
 
 ## Notes ##
 
-The class relies on ``strtotime()`` to make sense of your strings, and ``strftime()`` to make the format changes.  Just always check the ``time()`` output to see if you get false timestamps... which means the class couldn't understand what you were telling it.
+The class relies on ``strtotime()`` to make sense of your strings, and ``strftime()`` to handle the formatting. Always check the ``time()`` output to see if you get false timestamps, it which case, means the class couldn't understand what you were asking it to do.
 
 ## License ##
-- This bundle is created based on [Laravel-Date](https://github.com/swt83/laravel-date) by [Scott Travis](https://github.com/swt83) (MIT Licensed).  
-- [Jalali (Shamsi) DateTime](https://github.com/sallar/jDateTime) class included in the package is created by [Sallar Kaboli](http://sallar.me) and is released under the MIT License. 
-- This package was created by [Milad Rey](http://milad.io) and is released under the MIT License.
+- This bundle is created based on [Laravel-Date](https://github.com/swt83/laravel-date) by [Scott Travis](https://github.com/swt83) (MIT Licensed).
+- [Jalali (Shamsi) DateTime](https://github.com/sallar/CalendarUtils) class included in the package is created by [Sallar Kaboli](http://sallar.me) and is released under the MIT License.
+-  This package is created and modified by [Morteza Parvini](http://morilog.ir) for Laravel >= 5 and is released under the MIT License.
diff --git a/composer.json b/composer.json
index 3c9f6a7..036e98e 100644
--- a/composer.json
+++ b/composer.json
@@ -1,21 +1,38 @@
 {
-    "name": "miladr/jalali",
-    "description": "This Package helps developers to easily work with Jalali (Shamsi or Iranian) dates in Laravel 4 applications, based on Jalali (Shamsi) DateTime class. This Package is based on a Laravel 3 bundle sallar/laravel-jdate by Sallar Kaboli.",
+    "name": "moree-dev/jalali",
+    "description": "This Package helps developers to easily work with Jalali (Shamsi or Iranian) dates in PHP applications, based on Jalali (Shamsi) DateTime class.",
     "license": "MIT",
+    "type": "library",
     "authors": [
         {
             "name": "Milad Rey",
             "email": "miladr@gmail.com"
-        }
+        }, {
+		    "name": "Morteza Parvini",
+		    "email": "m.parvini@outlook.com"
+	    }
     ],
-    "keywords": ["Laravel","Date","Datetime","Jalali"],
+    "keywords": ["Laravel","Date","Datetime","Jalali", "Morilog"],
     "require": {
-        "php": ">=5.3.0"
+        "php": "^7.0 | ^8.0",
+        "nesbot/carbon": "^1.21 || ^2.0 || ^3.0",
+        "beberlei/assert": "^3.0"
+    },
+    "require-dev" : {
+        "phpunit/phpunit": ">4.0"
     },
     "autoload": {
-        "psr-0": {
-            "Miladr\\Jalali": "src/"
+        "psr-4": {
+            "Morilog\\Jalali\\": "src"
+        },
+        "files": [
+            "src/helpers.php"
+        ]
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "Morilog\\Jalali\\Tests\\": "tests/"
         }
     },
-    "minimum-stability": "dev"
+    "minimum-stablity": "dev"
 }
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..d2d2c99
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,16 @@
+
+
+    
+        
+            ./tests/
+        
+    
+
\ No newline at end of file
diff --git a/src/CalendarUtils.php b/src/CalendarUtils.php
new file mode 100644
index 0000000..aa288a8
--- /dev/null
+++ b/src/CalendarUtils.php
@@ -0,0 +1,857 @@
+setDate($year, $month, $day);
+
+
+        return $georgianDate;
+    }
+
+    /**
+     * Checks whether a Jalaali date is valid or not.
+     *
+     * @param int $jy
+     * @param int $jm
+     * @param int $jd
+     * @return bool
+     */
+    public static function isValidateJalaliDate($jy, $jm, $jd)
+    {
+        return $jy >= -61 && $jy <= 3177
+            && $jm >= 1 && $jm <= 12
+            && $jd >= 1 && $jd <= self::jalaliMonthLength($jy, $jm);
+    }
+
+    /**
+     * Checks whether a date is valid or not.
+     *
+     * @param $year
+     * @param $month
+     * @param $day
+     * @param bool $isJalali
+     * @return bool
+     */
+    public static function checkDate($year, $month, $day, $isJalali = true)
+    {
+        return $isJalali === true ? self::isValidateJalaliDate($year, $month, $day) : checkdate($month, $day, $year);
+    }
+
+    /**
+     *  Is this a leap year or not?
+     *
+     * @param $jy
+     * @return bool
+     */
+    public static function isLeapJalaliYear($jy)
+    {
+        return self::jalaliCal($jy)['leap'] === 0;
+    }
+
+    /**
+     * Number of days in a given month in a Jalaali year.
+     *
+     * @param int $jy
+     * @param int $jm
+     * @return int
+     */
+    public static function jalaliMonthLength($jy, $jm)
+    {
+        if ($jm <= 6) {
+            return 31;
+        }
+
+        if ($jm <= 11) {
+            return 30;
+        }
+
+        return self::isLeapJalaliYear($jy) ? 30 : 29;
+    }
+
+
+    /**
+     * This function determines if the Jalaali (Persian) year is
+     * leap (366-day long) or is the common year (365 days), and
+     * finds the day in March (Gregorian calendar) of the first
+     * day of the Jalaali year (jy).
+     *
+     * @param int $jy Jalaali calendar year (-61 to 3177)
+     * @return array
+     * leap: number of years since the last leap year (0 to 4)
+     * gy: Gregorian year of the beginning of Jalaali year
+     * march: the March day of Farvardin the 1st (1st day of jy)
+     * @see: http://www.astro.uni.torun.pl/~kb/Papers/EMP/PersianC-EMP.htm
+     * @see: http://www.fourmilab.ch/documents/calendar/
+     */
+    public static function jalaliCal($jy)
+    {
+        $breaks = [
+            -61, 9, 38, 199, 426, 686, 756, 818, 1111, 1181, 1210, 1635, 2060, 2097, 2192, 2262, 2324, 2394, 2456, 3178
+        ];
+
+        $breaksCount = count($breaks);
+
+        $gy = $jy + 621;
+        $leapJ = -14;
+        $jp = $breaks[0];
+
+        if ($jy < $jp || $jy >= $breaks[$breaksCount - 1]) {
+            throw new \InvalidArgumentException('Invalid Jalali year : ' . $jy);
+        }
+
+        $jump = 0;
+
+        for ($i = 1; $i < $breaksCount; $i += 1) {
+            $jm = $breaks[$i];
+            $jump = $jm - $jp;
+
+            if ($jy < $jm) {
+                break;
+            }
+
+            $leapJ = $leapJ + self::div($jump, 33) * 8 + self::div(self::mod($jump, 33), 4);
+
+            $jp = $jm;
+        }
+
+        $n = $jy - $jp;
+
+        $leapJ = $leapJ + self::div($n, 33) * 8 + self::div(self::mod($n, 33) + 3, 4);
+
+        if (self::mod($jump, 33) === 4 && $jump - $n === 4) {
+            $leapJ += 1;
+        }
+
+        $leapG = self::div($gy, 4) - self::div((self::div($gy, 100) + 1) * 3, 4) - 150;
+
+        $march = 20 + $leapJ - $leapG;
+
+        if ($jump - $n < 6) {
+            $n = $n - $jump + self::div($jump + 4, 33) * 33;
+        }
+
+        $leap = self::mod(self::mod($n + 1, 33) - 1, 4);
+
+        if ($leap === -1) {
+            $leap = 4;
+        }
+
+        return [
+            'leap' => $leap,
+            'gy' => $gy,
+            'march' => $march
+        ];
+    }
+
+    /**
+     * @param $a
+     * @param $b
+     */
+    public static function div($a, $b): int
+    {
+        return  intdiv($a, $b);
+    }
+
+    /**
+     * @param $a
+     * @param $b
+     * @return mixed
+     */
+    public static function mod($a, $b): int
+    {
+        return  $a - intdiv($a, $b) * $b;
+    }
+
+    /**
+     * @param $jdn
+     * @return array
+     */
+    public static function d2g($jdn)
+    {
+        $j = 4 * $jdn + 139361631;
+        $j += self::div(self::div(4 * $jdn + 183187720, 146097) * 3, 4) * 4 - 3908;
+        $i = self::div(self::mod($j, 1461), 4) * 5 + 308;
+
+        $gd = self::div(self::mod($i, 153), 5) + 1;
+        $gm = self::mod(self::div($i, 153), 12) + 1;
+        $gy = self::div($j, 1461) - 100100 + self::div(8 - $gm, 6);
+
+        return [$gy, $gm, $gd];
+    }
+
+    /**
+     * Calculates the Julian Day number from Gregorian or Julian
+     * calendar dates. This integer number corresponds to the noon of
+     * the date (i.e. 12 hours of Universal Time).
+     * The procedure was tested to be good since 1 March, -100100 (of both
+     * calendars) up to a few million years into the future.
+     *
+     * @param int $gy Calendar year (years BC numbered 0, -1, -2, ...)
+     * @param int $gm Calendar month (1 to 12)
+     * @param int $gd Calendar day of the month (1 to 28/29/30/31)
+     * @return int Julian Day number
+     */
+    public static function g2d($gy, $gm, $gd)
+    {
+        return (self::div(($gy + self::div($gm - 8, 6) + 100100) * 1461, 4)
+            + self::div(153 * self::mod($gm + 9, 12) + 2, 5)
+            + $gd - 34840408
+        ) - self::div(self::div($gy + 100100 + self::div($gm - 8, 6), 100) * 3, 4) + 752;
+    }
+
+    /**
+     * Converts a date of the Jalaali calendar to the Julian Day number.
+     *
+     * @param int $jy Jalaali year (1 to 3100)
+     * @param int $jm Jalaali month (1 to 12)
+     * @param int $jd Jalaali day (1 to 29/31)
+     * @return int  Julian Day number
+     */
+    public static function j2d($jy, $jm, $jd)
+    {
+        $jCal = self::jalaliCal($jy);
+
+        return self::g2d($jCal['gy'], 3, $jCal['march']) + ($jm - 1) * 31 - self::div($jm, 7) * ($jm - 7) + $jd - 1;
+    }
+
+
+    /**
+     * Converts the Julian Day number to a date in the Jalaali calendar.
+     *
+     * @param int $jdn Julian Day number
+     * @return array
+     * 0: Jalaali year (1 to 3100)
+     * 1: Jalaali month (1 to 12)
+     * 2: Jalaali day (1 to 29/31)
+     */
+    public static function d2j($jdn)
+    {
+        $gy = self::d2g($jdn)[0];
+        $jy = $gy - 621;
+        $jCal = self::jalaliCal($jy);
+        $jdn1f = self::g2d($gy, 3, $jCal['march']);
+
+        $k = $jdn - $jdn1f;
+
+        if ($k >= 0) {
+            if ($k <= 185) {
+                $jm = 1 + self::div($k, 31);
+                $jd = self::mod($k, 31) + 1;
+
+                return [$jy, $jm, $jd];
+            } else {
+                $k -= 186;
+            }
+        } else {
+            $jy -= 1;
+            $k += 179;
+
+            if ($jCal['leap'] === 1) {
+                $k += 1;
+            }
+        }
+
+        $jm = 7 + self::div($k, 30);
+        $jd = self::mod($k, 30) + 1;
+
+        return [$jy, $jm, $jd];
+    }
+
+    /**
+     * @param $format
+     * @param bool $stamp
+     * @param bool $timezone
+     * @return mixed
+     */
+    public static function date($format, $stamp = false, $timezone = null)
+    {
+        $stamp = ($stamp !== false) ? $stamp : time();
+        $dateTime = static::createDateTime($stamp, $timezone);
+
+
+        //Find what to replace
+        $chars = (preg_match_all('/([a-zA-Z]{1})/', $format, $chars)) ? $chars[0] : array();
+
+        //Intact Keys
+        $intact = array('B', 'h', 'H', 'g', 'G', 'i', 's', 'I', 'U', 'u', 'Z', 'O', 'P');
+        $intact = self::filterArray($chars, $intact);
+        $intactValues = array();
+
+        foreach ($intact as $k => $v) {
+            $intactValues[$k] = $dateTime->format($v);
+        }
+        //End Intact Keys
+
+        //Changed Keys
+        list($year, $month, $day) = array($dateTime->format('Y'), $dateTime->format('n'), $dateTime->format('j'));
+        list($jYear, $jMonth, $jDay) = self::toJalali($year, $month, $day);
+
+        $keys = array(
+            'd',
+            'D',
+            'j',
+            'l',
+            'N',
+            'S',
+            'w',
+            'z',
+            'W',
+            'F',
+            'm',
+            'M',
+            'n',
+            't',
+            'L',
+            'o',
+            'Y',
+            'y',
+            'a',
+            'A',
+            'c',
+            'r',
+            'e',
+            'T'
+        );
+        $keys = self::filterArray($chars, $keys, array('z'));
+        $values = array();
+
+        foreach ($keys as $k => $key) {
+            $v = '';
+            switch ($key) {
+                //Day
+                case 'd':
+                    $v = sprintf("%02d", $jDay);
+                    break;
+                case 'D':
+                    $v = self::getDayNames($dateTime->format('D'), true);
+                    break;
+                case 'j':
+                    $v = $jDay;
+                    break;
+                case 'l':
+                    $v = self::getDayNames($dateTime->format('l'));
+                    break;
+                case 'N':
+                    $v = self::getDayNames($dateTime->format('l'), false, 1, true);
+                    break;
+                case 'S':
+                    $v = 'ام';
+                    break;
+                case 'w':
+                    $v = self::getDayNames($dateTime->format('l'), false, 1, true) - 1;
+                    break;
+                case 'z':
+                    if ($jMonth > 6) {
+                        $v = 186 + (($jMonth - 6 - 1) * 30) + $jDay;
+                    } else {
+                        $v = (($jMonth - 1) * 31) + $jDay;
+                    }
+                    self::$temp['z'] = $v;
+                    break;
+                    //Week
+                case 'W':
+                    $v = is_int(self::$temp['z'] / 7) ? (self::$temp['z'] / 7) : intval(self::$temp['z'] / 7 + 1);
+                    break;
+                    //Month
+                case 'F':
+                    $v = self::getMonthName($jMonth);
+                    break;
+                case 'm':
+                    $v = sprintf("%02d", $jMonth);
+                    break;
+                case 'M':
+                    $v = self::getMonthName($jMonth, true);
+                    break;
+                case 'n':
+                    $v = $jMonth;
+                    break;
+                case 't':
+                    $v = ($jMonth == 12) ? (self::isLeapJalaliYear($jYear) ? 30 : 29) : ($jMonth > 6 ? 30 : 31);
+                    break;
+                    //Year
+                case 'L':
+                    $tmpObj = static::createDateTime(time() - 31536000, $timezone);
+                    $v = $tmpObj->format('L');
+                    break;
+                case 'o':
+                case 'Y':
+                    $v = $jYear;
+                    break;
+                case 'y':
+                    $v = $jYear % 100;
+                    if ($v < 10) {
+                        $v = '0' . $v;
+                    }
+                    break;
+                    //Time
+                case 'a':
+                    $v = ($dateTime->format('a') == 'am') ? 'ق.ظ' : 'ب.ظ';
+                    break;
+                case 'A':
+                    $v = ($dateTime->format('A') == 'AM') ? 'قبل از ظهر' : 'بعد از ظهر';
+                    break;
+                    //Full Dates
+                case 'c':
+                    $v = $jYear . '-' . sprintf("%02d", $jMonth) . '-' . sprintf("%02d", $jDay) . 'T';
+                    $v .= $dateTime->format('H') . ':' . $dateTime->format('i') . ':' . $dateTime->format('s') . $dateTime->format('P');
+                    break;
+                case 'r':
+                    $v = self::getDayNames($dateTime->format('D'), true) . ', ' . sprintf(
+                        "%02d",
+                        $jDay
+                    ) . ' ' . self::getMonthName($jMonth, true);
+                    $v .= ' ' . $jYear . ' ' . $dateTime->format('H') . ':' . $dateTime->format('i') . ':' . $dateTime->format('s') . ' ' . $dateTime->format('P');
+                    break;
+                    //Timezone
+                case 'e':
+                    $v = $dateTime->format('e');
+                    break;
+                case 'T':
+                    $v = $dateTime->format('T');
+                    break;
+            }
+            $values[$k] = $v;
+        }
+        //End Changed Keys
+
+        //Merge
+        $keys = array_merge($intact, $keys);
+        $values = array_merge($intactValues, $values);
+
+        return strtr($format, array_combine($keys, $values));
+    }
+
+    /**
+     * @param $format
+     * @param bool $stamp
+     * @param null $timezone
+     * @return mixed
+     */
+    public static function strftime($format, $stamp = false, $timezone = null)
+    {
+        $str_format_code = array(
+            "%a",
+            "%A",
+            "%d",
+            "%e",
+            "%j",
+            "%u",
+            "%w",
+            "%U",
+            "%V",
+            "%W",
+            "%b",
+            "%B",
+            "%h",
+            "%m",
+            "%C",
+            "%g",
+            "%G",
+            "%y",
+            "%Y",
+            "%H",
+            "%I",
+            "%l",
+            "%M",
+            "%p",
+            "%P",
+            "%r",
+            "%R",
+            "%S",
+            "%T",
+            "%X",
+            "%z",
+            "%Z",
+            "%c",
+            "%D",
+            "%F",
+            "%s",
+            "%x",
+            "%n",
+            "%t",
+            "%%",
+        );
+
+        $date_format_code = array(
+            "D",
+            "l",
+            "d",
+            "j",
+            "z",
+            "N",
+            "w",
+            "W",
+            "W",
+            "W",
+            "M",
+            "F",
+            "M",
+            "m",
+            "y",
+            "y",
+            "y",
+            "y",
+            "Y",
+            "H",
+            "h",
+            "g",
+            "i",
+            "A",
+            "a",
+            "h:i:s A",
+            "H:i",
+            "s",
+            "H:i:s",
+            "h:i:s",
+            "H",
+            "H",
+            "D j M H:i:s",
+            "d/m/y",
+            "Y-m-d",
+            "U",
+            "d/m/y",
+            "\n",
+            "\t",
+            "%",
+        );
+
+        //Change Strftime format to Date format
+        $format = str_replace($str_format_code, $date_format_code, $format);
+
+        //Convert to date
+        return self::date($format, $stamp, $timezone);
+    }
+
+    private static function getDayNames($day, $shorten = false, $len = 1, $numeric = false)
+    {
+        switch (strtolower($day)) {
+            case 'sat':
+            case 'saturday':
+                $ret = 'شنبه';
+                $n = 1;
+                break;
+            case 'sun':
+            case 'sunday':
+                $ret = 'یکشنبه';
+                $n = 2;
+                break;
+            case 'mon':
+            case 'monday':
+                $ret = 'دوشنبه';
+                $n = 3;
+                break;
+            case 'tue':
+            case 'tuesday':
+                $ret = 'سهشنبه';
+                $n = 4;
+                break;
+            case 'wed':
+            case 'wednesday':
+                $ret = 'چهارشنبه';
+                $n = 5;
+                break;
+            case 'thu':
+            case 'thursday':
+                $ret = 'پنجشنبه';
+                $n = 6;
+                break;
+            case 'fri':
+            case 'friday':
+                $ret = 'جمعه';
+                $n = 7;
+                break;
+            default:
+                $ret = '';
+                $n = -1;
+        }
+
+        return ($numeric) ? $n : (($shorten) ? mb_substr($ret, 0, $len, 'UTF-8') : $ret);
+    }
+
+    private static function getMonthName($month, $shorten = false, $len = 3)
+    {
+        $monthIndex = ((int)$month) -1 ;
+        $monthName = static::$monthNames[$monthIndex];
+        return ($shorten) ? mb_substr($monthName, 0, $len, 'UTF-8') : $monthName;
+    }
+
+    private static function filterArray($needle, $haystack, $always = array())
+    {
+        foreach ($haystack as $k => $v) {
+            if (!in_array($v, $needle) && !in_array($v, $always)) {
+                unset($haystack[$k]);
+            }
+        }
+
+
+        return $haystack;
+    }
+
+
+    /**
+     * @param $format
+     * @param $date
+     * @return array
+     */
+    public static function parseFromFormat($format, $date)
+    {
+        // reverse engineer date formats
+        $keys = array(
+            'Y' => array('year', '\d{4}'),
+            'y' => array('year', '\d{2}'),
+            'm' => array('month', '\d{2}'),
+            'n' => array('month', '\d{1,2}'),
+            'M' => array('month', '[A-Z][a-z]{3}'),
+            'F' => array('month', '[A-Z][a-z]{2,8}'),
+            'd' => array('day', '\d{2}'),
+            'j' => array('day', '\d{1,2}'),
+            'D' => array('day', '[A-Z][a-z]{2}'),
+            'l' => array('day', '[A-Z][a-z]{6,9}'),
+            'u' => array('hour', '\d{1,6}'),
+            'h' => array('hour', '\d{2}'),
+            'H' => array('hour', '\d{2}'),
+            'g' => array('hour', '\d{1,2}'),
+            'G' => array('hour', '\d{1,2}'),
+            'i' => array('minute', '\d{2}'),
+            's' => array('second', '\d{2}'),
+        );
+
+        // convert format string to regex
+        $regex = '';
+        $chars = str_split($format);
+        foreach ($chars as $n => $char) {
+            $lastChar = isset($chars[$n - 1]) ? $chars[$n - 1] : '';
+            $skipCurrent = '\\' == $lastChar;
+            if (!$skipCurrent && isset($keys[$char])) {
+                $regex .= '(?P<' . $keys[$char][0] . '>' . $keys[$char][1] . ')';
+            } else {
+                if ('\\' == $char) {
+                    $regex .= $char;
+                } else {
+                    $regex .= preg_quote($char);
+                }
+            }
+        }
+
+        $dt = array();
+        $dt['error_count'] = 0;
+        // now try to match it
+        if (preg_match('#^' . $regex . '$#', $date, $dt)) {
+            foreach ($dt as $k => $v) {
+                if (is_int($k)) {
+                    unset($dt[$k]);
+                }
+            }
+            if (!CalendarUtils::checkdate($dt['month'], $dt['day'], $dt['year'], false)) {
+                $dt['error_count'] = 1;
+            }
+        } else {
+            $dt['error_count'] = 1;
+        }
+        $dt['errors'] = array();
+        $dt['fraction'] = '';
+        $dt['warning_count'] = 0;
+        $dt['warnings'] = array();
+        $dt['is_localtime'] = 0;
+        $dt['zone_type'] = 0;
+        $dt['zone'] = 0;
+        $dt['is_dst'] = '';
+
+        if (strlen($dt['year']) == 2) {
+            $now = Jalalian::forge('now');
+            $x = $now->format('Y') - $now->format('y');
+            $dt['year'] += $x;
+        }
+
+        $dt['year'] = isset($dt['year']) ? (int)$dt['year'] : 0;
+        $dt['month'] = isset($dt['month']) ? (int)$dt['month'] : 0;
+        $dt['day'] = isset($dt['day']) ? (int)$dt['day'] : 0;
+        $dt['hour'] = isset($dt['hour']) ? (int)$dt['hour'] : 0;
+        $dt['minute'] = isset($dt['minute']) ? (int)$dt['minute'] : 0;
+        $dt['second'] = isset($dt['second']) ? (int)$dt['second'] : 0;
+
+        return $dt;
+    }
+
+    /**
+     * @param $format
+     * @param $str
+     * @param null $timezone
+     * @return \DateTime
+     */
+    public static function createDatetimeFromFormat($format, $str, $timezone = null)
+    {
+        $pd = self::parseFromFormat($format, $str);
+        $gd = self::toGregorian($pd['year'], $pd['month'], $pd['day']);
+        $date = self::createDateTime('now', $timezone);
+        $date->setDate($gd[0], $gd[1], $gd[2]);
+        $date->setTime($pd['hour'], $pd['minute'], $pd['second']);
+
+        return $date;
+    }
+
+    /**
+     * @param $format
+     * @param $str
+     * @param null $timezone
+     * @return Carbon
+     */
+    public static function createCarbonFromFormat($format, $str, $timezone = null)
+    {
+        $dateTime = self::createDatetimeFromFormat($format, $str, $timezone);
+
+        return Carbon::createFromTimestamp($dateTime->getTimestamp(), $dateTime->getTimezone());
+    }
+
+    /**
+     * Convert Latin numbers to persian numbers and vice versa
+     *
+     * @param string $string
+     * @param boolean $toEnglish, default is false to save compatiblity
+     * @return string
+     */
+    public static function convertNumbers($string, $toLatin = false)
+    {
+        $farsi_array = array("۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹");
+        $english_array = array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
+        if (!$toLatin) {
+            return str_replace($english_array, $farsi_array, $string);
+        }
+        return str_replace($farsi_array, $english_array, $string);
+    }
+
+    /**
+     * @param $timestamp
+     * @param null $timezone
+     * @return \DateTime|static
+     */
+    public static function createDateTime($timestamp = null, $timezone = null)
+    {
+        $timezone = static::createTimeZone($timezone);
+
+        if ($timestamp === null) {
+            return Carbon::now($timezone);
+        }
+
+
+        if ($timestamp instanceof \DateTimeInterface) {
+            return $timestamp;
+        }
+
+        if (is_string($timestamp)) {
+            return new \DateTime($timestamp, $timezone);
+        }
+
+        if (is_numeric($timestamp)) {
+            return Carbon::createFromTimestamp($timestamp, $timezone);
+        }
+
+
+        throw new \InvalidArgumentException('timestamp is not valid');
+    }
+
+    /**
+     * @param null $timezone
+     * @return \DateTimeZone|null
+     */
+    public static function createTimeZone($timezone = null)
+    {
+        if ($timezone instanceof \DateTimeZone) {
+            return $timezone;
+        }
+
+        if ($timezone === null) {
+            return new \DateTimeZone(date_default_timezone_get());
+        }
+
+        if (is_string($timezone)) {
+            return new \DateTimeZone($timezone);
+        }
+
+
+        throw new \InvalidArgumentException('timezone is not valid');
+    }
+}
diff --git a/src/Converter.php b/src/Converter.php
new file mode 100644
index 0000000..78ca211
--- /dev/null
+++ b/src/Converter.php
@@ -0,0 +1,170 @@
+format("Y/m/d");
+    }
+
+    /**
+     * Format the instance as a readable date
+     *
+     * @return string
+     */
+    public function toFormattedDateString()
+    {
+        return $this->format('j F Y');
+    }
+
+    /**
+     * Format the instance with the day, and a readable date
+     *
+     * @return string
+     */
+    public function toFormattedDayDateString()
+    {
+        return $this->format('l j F Y');
+    }
+
+    /**
+     * Format the instance as time
+     *
+     * @param string $unitPrecision
+     *
+     * @return string
+     */
+    public function toTimeString($unitPrecision = 'second')
+    {
+        return $this->format(static::getTimeFormatByPrecision($unitPrecision));
+    }
+
+    /**
+     * Format the instance as date and time
+     *
+     * @param string $unitPrecision
+     *
+     * @return string
+     */
+    public function toDateTimeString($unitPrecision = 'second')
+    {
+        return $this->format('Y/m/d ' . static::getTimeFormatByPrecision($unitPrecision));
+    }
+
+    /**
+     * Format the instance as a readable date and time
+     *
+     * @param string $unitPrecision
+     *
+     * @return string
+     */
+    public function toFormattedDateTimeString($unitPrecision = 'second')
+    {
+        return $this->format('j F Y ' . static::getTimeFormatByPrecision($unitPrecision));
+    }
+
+    /**
+     * Return a format from H:i to H:i:s.u according to given unit precision.
+     *
+     * @param string $unitPrecision "minute", "second", "millisecond" or "microsecond"
+     *
+     * @return string
+     */
+    public static function getTimeFormatByPrecision($unitPrecision)
+    {
+        switch (Date::singularUnit($unitPrecision)) {
+            case 'minute':
+                return 'H:i';
+            case 'second':
+                return 'H:i:s';
+            case 'm':
+            case 'millisecond':
+                return 'H:i:s.v';
+            case 'µ':
+            case 'microsecond':
+                return 'H:i:s.u';
+        }
+
+        throw new UnitException('Precision unit expected among: minute, second, millisecond and microsecond.');
+    }
+
+    /**
+     * Format the instance as date and time T-separated with no timezone
+     * echo Jalalian::now()->toDateTimeLocalString('minute'); // You can specify precision among: minute, second, millisecond and microsecond
+     * ```
+     *
+     * @param string $unitPrecision
+     *
+     * @return string
+     */
+    public function toDateTimeLocalString($unitPrecision = 'second')
+    {
+        return $this->format('Y-m-d\T' . static::getTimeFormatByPrecision($unitPrecision));
+    }
+
+    /**
+     * Format the instance with day, date and time
+     *
+     * @param string $unitPrecision
+     *
+     * @return string
+     */
+    public function toDayDateTimeString($unitPrecision = 'second')
+    {
+        return $this->format('l j F Y ' . static::getTimeFormatByPrecision($unitPrecision));
+    }
+
+    /**
+     * Format the instance with the year, and a readable month
+     *
+     * @return string
+     */
+    public function toFormattedMonthYearString()
+    {
+        return $this->format('F Y');
+    }
+
+    /**
+     * Change persian day name to CarbonInterface
+     * 
+     * @param string $modifier
+     * 
+     * @return int
+     */
+    public function toCarbonDayName(string $modifier): int
+    {
+        $carbonDayModifiers = [
+            'شنبه'  => CarbonInterface::SATURDAY,
+            'یکشنبه' => CarbonInterface::SUNDAY,
+            'دوشنبه' => CarbonInterface::MONDAY,
+            'سهشنبه' => CarbonInterface::TUESDAY,
+            'چهارشنبه' => CarbonInterface::WEDNESDAY,
+            'پنجشنبه' => CarbonInterface::THURSDAY,
+            'جمعه' => CarbonInterface::FRIDAY,
+        ];
+
+        if (!isset($carbonDayModifiers[$modifier])) {
+            throw new \InvalidArgumentException('Modifier expected among: شنبه, یکشنبه, دوشنبه, سهشنبه, چهارشنبه, پنجشنبه و جمعه.');
+        }
+
+        return $carbonDayModifiers[$modifier];
+    }
+}
diff --git a/src/Jalalian.php b/src/Jalalian.php
new file mode 100644
index 0000000..75738ab
--- /dev/null
+++ b/src/Jalalian.php
@@ -0,0 +1,806 @@
+ 6) {
+            Assertion::between($day, 1, 30);
+        }
+
+        if (!CalendarUtils::isLeapJalaliYear($year) && $month === 12) {
+            Assertion::between($day, 1, 29);
+        }
+        Assertion::between($hour, 0, 24);
+        Assertion::between($minute, 0, 59);
+        Assertion::between($second, 0, 59);
+
+        $this->year = $year;
+        $this->month = $month;
+        $this->day = $day;
+        $this->hour = $hour;
+        $this->minute = $minute;
+        $this->second = $second;
+        $this->timezone = $timezone;
+    }
+
+    public static function now(\DateTimeZone $timeZone = null): Jalalian
+    {
+        return static::fromCarbon(Carbon::now($timeZone));
+    }
+
+    /**
+     * @param Carbon $carbon
+     * @return Jalalian
+     */
+    public static function fromCarbon(Carbon $carbon): Jalalian
+    {
+        $jDate = CalendarUtils::toJalali($carbon->year, $carbon->month, $carbon->day);
+
+        return new static(
+            $jDate[0],
+            $jDate[1],
+            $jDate[2],
+            $carbon->hour,
+            $carbon->minute,
+            $carbon->second,
+            $carbon->getTimezone()
+        );
+    }
+
+    public static function fromFormat(string $format, string $timestamp, \DateTimeZone $timeZone = null): Jalalian
+    {
+        return static::fromCarbon(CalendarUtils::createCarbonFromFormat($format, $timestamp, $timeZone));
+    }
+
+    public static function forge($timestamp, \DateTimeZone $timeZone = null): Jalalian
+    {
+        return static::fromDateTime($timestamp, $timeZone);
+    }
+
+    /**
+     * @param \DateTimeInterface| string $dateTime
+     * @param \DateTimeZone|null $timeZone
+     * @return Jalalian
+     */
+    public static function fromDateTime($dateTime, \DateTimeZone $timeZone = null): Jalalian
+    {
+        if (is_numeric($dateTime)) {
+            return static::fromCarbon(Carbon::createFromTimestamp($dateTime, $timeZone));
+        }
+
+        return static::fromCarbon(new Carbon($dateTime, $timeZone));
+    }
+
+    public function getFirstDayOfWeek(): Jalalian
+    {
+        return (new static(
+            $this->getYear(),
+            $this->getMonth(),
+            $this->getDay(),
+            $this->getHour(),
+            $this->getMinute(),
+            $this->getSecond(),
+            $this->getTimezone()
+        ))->subDays($this->getDayOfWeek());
+    }
+
+    public function getFirstDayOfMonth(): Jalalian
+    {
+        return new static(
+            $this->getYear(),
+            $this->getMonth(),
+            1,
+            $this->getHour(),
+            $this->getMinute(),
+            $this->getSecond(),
+            $this->getTimezone()
+        );
+    }
+
+    public function getFirstDayOfYear(): Jalalian
+    {
+        return new static(
+            $this->getYear(),
+            1,
+            1,
+            $this->getHour(),
+            $this->getMinute(),
+            $this->getSecond(),
+            $this->getTimezone()
+        );
+    }
+
+    public function getFirstDayOfQuarter(): Jalalian
+    {
+        return new static(
+            $this->getYear(),
+            ($this->getQuarter() - 1) * Carbon::MONTHS_PER_QUARTER + 1,
+            1,
+            $this->getHour(),
+            $this->getMinute(),
+            $this->getSecond(),
+            $this->getTimezone()
+        );
+    }
+
+    public function getEndDayOfWeek(): Jalalian
+    {
+        $endWeek = $this->addDays(6 - $this->getDayOfWeek());
+
+        return (new static(
+            $endWeek->getYear(),
+            $endWeek->getMonth(),
+            $endWeek->getDay(),
+            $endWeek->getHour(),
+            $endWeek->getMinute(),
+            $endWeek->getSecond(),
+            $endWeek->getTimezone()
+        ));
+    }
+
+    public function getEndDayOfMonth(): Jalalian
+    {
+        return new static(
+            $this->getYear(),
+            $this->getMonth(),
+            $this->getDaysOf($this->getMonth()),
+            $this->getHour(),
+            $this->getMinute(),
+            $this->getSecond(),
+            $this->getTimezone()
+        );
+    }
+
+    public function getEndDayOfYear(): Jalalian
+    {
+        return new static(
+            $this->getYear(),
+            12,
+            $this->getDaysOf(12),
+            $this->getHour(),
+            $this->getMinute(),
+            $this->getSecond(),
+            $this->getTimezone()
+        );
+    }
+
+    public function getEndDayOfQuarter(): Jalalian
+    {
+        return new static(
+            $this->getYear(),
+            $this->getQuarter() * Carbon::MONTHS_PER_QUARTER,
+            $this->getDaysOf($this->getQuarter() * Carbon::MONTHS_PER_QUARTER),
+            $this->getHour(),
+            $this->getMinute(),
+            $this->getSecond(),
+            $this->getTimezone()
+        );
+    }
+
+    public function getMonthDays()
+    {
+        if ($this->getMonth() <= 6) {
+            return 31;
+        }
+
+        if ($this->getMonth() < 12 || $this->isLeapYear()) {
+            return 30;
+        }
+
+        return 29;
+    }
+
+    /**
+     * @return int
+     */
+    public function getMonth(): int
+    {
+        return $this->month;
+    }
+
+    public function isLeapYear(): bool
+    {
+        return CalendarUtils::isLeapJalaliYear($this->getYear());
+    }
+
+    /**
+     * @return int
+     */
+    public function getYear()
+    {
+        return $this->year;
+    }
+
+    public function getQuarter(): int
+    {
+        return (int) ceil($this->getMonth() / Carbon::MONTHS_PER_QUARTER);
+    }
+
+    public function subMonths(int $months = 1): Jalalian
+    {
+        Assertion::greaterOrEqualThan($months, 1);
+
+        $diff = ($this->getMonth() - $months);
+
+        if ($diff >= 1) {
+            $day = $this->getDay();
+            $targetMonthDays = $this->getDaysOf($diff);
+            $targetDay = $day <= $targetMonthDays ? $day : $targetMonthDays;
+
+            return new static(
+                $this->getYear(),
+                $diff,
+                $targetDay,
+                $this->getHour(),
+                $this->getMinute(),
+                $this->getSecond(),
+                $this->getTimezone()
+            );
+        }
+
+        $years = abs((int)($diff / 12));
+        $date = $years > 0 ? $this->subYears($years) : clone $this;
+        $diff = 12 - abs($diff % 12) - $date->getMonth();
+
+        return $diff > 0 ? $date->subYears(1)->addMonths($diff) : $date->subYears(1);
+    }
+
+    /**
+     * @return int
+     */
+    public function getDay(): int
+    {
+        return $this->day;
+    }
+
+    public function getDaysOf(int $monthNumber = 1): int
+    {
+        Assertion::between($monthNumber, 1, 12);
+
+        $months = [
+            1 => 31,
+            2 => 31,
+            3 => 31,
+            4 => 31,
+            5 => 31,
+            6 => 31,
+            7 => 30,
+            8 => 30,
+            9 => 30,
+            10 => 30,
+            11 => 30,
+            12 => $this->isLeapYear() ? 30 : 29,
+        ];
+
+        return $months[$monthNumber];
+    }
+
+    /**
+     * @return int
+     */
+    public function getHour(): int
+    {
+        return $this->hour;
+    }
+
+    /**
+     * @return int
+     */
+    public function getMinute(): int
+    {
+        return $this->minute;
+    }
+
+    /**
+     * @return int
+     */
+    public function getSecond(): int
+    {
+        return $this->second;
+    }
+
+    /**
+     * @return \DateTimeZone|null
+     */
+    public function getTimezone()
+    {
+        return $this->timezone;
+    }
+
+    public function subYears(int $years = 1): Jalalian
+    {
+        Assertion::greaterOrEqualThan($years, 1);
+
+        return new static(
+            $this->getYear() - $years,
+            $this->getMonth(),
+            $this->getDay(),
+            $this->getHour(),
+            $this->getMinute(),
+            $this->getSecond(),
+            $this->getTimezone()
+        );
+    }
+
+    public function addMonths(int $months = 1): Jalalian
+    {
+        Assertion::greaterOrEqualThan($months, 1);
+
+        $years = (int)($months / 12);
+        $months = (int)($months % 12);
+        $date = $years > 0 ? $this->addYears($years) : clone $this;
+
+        while ($months > 0) {
+            $nextMonth = ($date->getMonth() + 1) % 12;
+            $nextMonthDays = $date->getDaysOf($nextMonth === 0 ? 12 : $nextMonth);
+            $nextMonthDay = $date->getDay() <= $nextMonthDays ? $date->getDay() : $nextMonthDays;
+
+            $days = ($date->getMonthDays() - $date->getDay()) + $nextMonthDay;
+
+            $date = $date->addDays($days);
+            $months--;
+        }
+
+        return $date;
+    }
+
+    public function addYears(int $years = 1): Jalalian
+    {
+        Assertion::greaterOrEqualThan($years, 1);
+
+        $year = $this->getYear() + $years;
+        if (false === CalendarUtils::isLeapJalaliYear($year) && $this->getMonth() === 12 && $this->getDay() === $this->getDaysOf(12)) {
+            $day = 29;
+        } else {
+            $day = $this->getDay();
+        }
+
+        return new static(
+            $year,
+            $this->getMonth(),
+            $day,
+            $this->getHour(),
+            $this->getMinute(),
+            $this->getSecond(),
+            $this->getTimezone()
+        );
+    }
+
+    public function subDays(int $days = 1): Jalalian
+    {
+        return static::fromCarbon($this->toCarbon()->subDays($days));
+    }
+
+    public function subDay(): Jalalian
+    {
+        return $this->subDays(1);
+    }
+
+    /**
+     * @return Carbon
+     */
+    public function toCarbon(): Carbon
+    {
+        $gDate = CalendarUtils::toGregorian($this->getYear(), $this->getMonth(), $this->getDay());
+        $carbon = Carbon::createFromDate($gDate[0], $gDate[1], $gDate[2], $this->getTimezone());
+
+        $carbon->setTime($this->getHour(), $this->getMinute(), $this->getSecond());
+
+        return $carbon;
+    }
+
+    public function addHours(int $hours = 1): Jalalian
+    {
+        return static::fromCarbon($this->toCarbon()->addHours($hours));
+    }
+
+    public function subHours(int $hours = 1): Jalalian
+    {
+        return static::fromCarbon($this->toCarbon()->subHours($hours));
+    }
+
+    public function addMinutes(int $minutes = 1): Jalalian
+    {
+        return static::fromCarbon($this->toCarbon()->addMinutes($minutes));
+    }
+
+    public function subMinutes(int $minutes = 1): Jalalian
+    {
+        return static::fromCarbon($this->toCarbon()->subMinutes($minutes));
+    }
+
+    public function addSeconds(int $secs = 1): Jalalian
+    {
+        return static::fromCarbon($this->toCarbon()->addSeconds($secs));
+    }
+
+    public function subSeconds(int $secs = 1): Jalalian
+    {
+        return static::fromCarbon($this->toCarbon()->subSeconds($secs));
+    }
+
+    public function equalsTo(Jalalian $other): bool
+    {
+        return $this->equalsToCarbon($other->toCarbon());
+    }
+
+    public function equalsToCarbon(Carbon $carbon): bool
+    {
+        return $this->toCarbon()->equalTo($carbon);
+    }
+
+    public function greaterThan(Jalalian $other): bool
+    {
+        return $this->greaterThanCarbon($other->toCarbon());
+    }
+
+    public function greaterThanCarbon(Carbon $carbon): bool
+    {
+        return $this->toCarbon()->greaterThan($carbon);
+    }
+
+    public function lessThan(Jalalian $other): bool
+    {
+        return $this->lessThanCarbon($other->toCarbon());
+    }
+
+    public function lessThanCarbon(Carbon $carbon): bool
+    {
+        return $this->toCarbon()->lessThan($carbon);
+    }
+
+    public function greaterThanOrEqualsTo(Jalalian $other): bool
+    {
+        return $this->greaterThanOrEqualsToCarbon($other->toCarbon());
+    }
+
+    public function greaterThanOrEqualsToCarbon(Carbon $carbon): bool
+    {
+        return $this->toCarbon()->greaterThanOrEqualTo($carbon);
+    }
+
+    public function lessThanOrEqualsTo(Jalalian $other): bool
+    {
+        return $this->lessThanOrEqualsToCarbon($other->toCarbon());
+    }
+
+    public function lessThanOrEqualsToCarbon(Carbon $carbon): bool
+    {
+        return $this->toCarbon()->lessThanOrEqualTo($carbon);
+    }
+
+    public function isStartOfWeek(): bool
+    {
+        return $this->isSaturday();
+    }
+
+    public function isSaturday(): bool
+    {
+        return $this->isDayOfWeek(Carbon::SATURDAY);
+    }
+
+    public function isDayOfWeek(int $day): bool
+    {
+        Assertion::between($day, 0, 6);
+        return $this->toCarbon()->isDayOfWeek($day);
+    }
+
+    public function isEndOfWeek(): bool
+    {
+        return $this->isFriday();
+    }
+
+    public function isFriday(): bool
+    {
+        return $this->isDayOfWeek(Carbon::FRIDAY);
+    }
+
+    public function isToday(): bool
+    {
+        return $this->toCarbon()->isToday();
+    }
+
+    public function isTomorrow(): bool
+    {
+        return $this->toCarbon()->isTomorrow();
+    }
+
+    public function isYesterday(): bool
+    {
+        return $this->toCarbon()->isYesterday();
+    }
+
+    public function isFuture(): bool
+    {
+        return $this->toCarbon()->isFuture();
+    }
+
+    public function isPast(): bool
+    {
+        return $this->toCarbon()->isPast();
+    }
+
+    public function toArray(): array
+    {
+        return [
+            'year' => $this->year,
+            'month' => $this->month,
+            'day' => $this->day,
+            'dayOfWeek' => $this->getDayOfWeek(),
+            'dayOfYear' => $this->getDayOfYear(),
+            'hour' => $this->hour,
+            'minute' => $this->minute,
+            'second' => $this->second,
+            'micro' => $this->toCarbon()->micro,
+            'timestamp' => $this->toCarbon()->timestamp,
+            'formatted' => $this->toString(),
+            'timezone' => $this->timezone,
+        ];
+    }
+
+    public function getDayOfWeek(): int
+    {
+        if ($this->isSaturday()) {
+            return 0;
+        }
+
+        if ($this->isSunday()) {
+            return 1;
+        }
+
+        if ($this->isMonday()) {
+            return 2;
+        }
+
+        if ($this->isTuesday()) {
+            return 3;
+        }
+
+        if ($this->isWednesday()) {
+            return 4;
+        }
+
+        if ($this->isThursday()) {
+            return 5;
+        }
+
+        return 6;
+    }
+
+    public function isSunday(): bool
+    {
+        return $this->isDayOfWeek(Carbon::SUNDAY);
+    }
+
+    public function isMonday(): bool
+    {
+        return $this->isDayOfWeek(Carbon::MONDAY);
+    }
+
+    public function isTuesday(): bool
+    {
+        return $this->isDayOfWeek(Carbon::TUESDAY);
+    }
+
+    public function isWednesday(): bool
+    {
+        return $this->isDayOfWeek(Carbon::WEDNESDAY);
+    }
+
+    public function isThursday(): bool
+    {
+        return $this->isDayOfWeek(Carbon::THURSDAY);
+    }
+
+    public function getDayOfYear(): int
+    {
+        $dayOfYear = 0;
+        for ($m = 1; $m < $this->getMonth(); $m++) {
+            if ($m <= 6) {
+                $dayOfYear += 31;
+                continue;
+            }
+
+            if ($m < 12) {
+                $dayOfYear += 30;
+                continue;
+            }
+        }
+
+        return $dayOfYear + $this->getDay();
+    }
+
+    public function toString(): string
+    {
+        return $this->format('Y-m-d H:i:s');
+    }
+
+    public function format(string $format): string
+    {
+        return CalendarUtils::strftime($format, $this->toCarbon());
+    }
+
+    public function __toString(): string
+    {
+        return $this->toString();
+    }
+
+    public function ago(): string
+    {
+        $now = time();
+        $time = $this->getTimestamp();
+
+        // catch error
+        if (!$time) {
+            return false;
+        }
+
+        // build period and length arrays
+        $periods = ['ثانیه', 'دقیقه', 'ساعت', 'روز', 'هفته', 'ماه', 'سال', 'قرن'];
+        $lengths = [60, 60, 24, 7, 4.35, 12, 10];
+
+        // get difference
+        $difference = $now - $time;
+
+        // set descriptor
+        if ($difference < 0) {
+            $difference = abs($difference); // absolute value
+            $negative = true;
+        }
+
+        // do math
+        for ($j = 0; $difference >= $lengths[$j] and $j < count($lengths) - 1; $j++) {
+            $difference /= $lengths[$j];
+        }
+
+        // round difference
+        $difference = intval(round($difference));
+
+        // return
+        return number_format($difference) . ' ' . $periods[$j] . ' ' . (isset($negative) ? '' : 'پیش');
+    }
+
+    public function getTimestamp(): int
+    {
+        return $this->toCarbon()->getTimestamp();
+    }
+
+    public function getNextWeek(): Jalalian
+    {
+        return $this->addDays(7);
+    }
+
+    public function getLastWeek(): Jalalian
+    {
+        return $this->subDays(7);
+    }
+
+    public function addDays(int $days = 1): Jalalian
+    {
+        return static::fromCarbon($this->toCarbon()->addDays($days));
+    }
+
+    public function addDay(): Jalalian
+    {
+        return $this->addDays(1);
+    }
+
+    public function getNextMonth(): Jalalian
+    {
+        return $this->addMonths(1);
+    }
+
+    public function getLastMonth(): Jalalian
+    {
+        return $this->subMonths(1);
+    }
+
+    public function getWeekOfMonth(): int
+    {
+        return floor(($this->day + 5 - $this->getDayOfWeek()) / 7) + 1;
+    }
+
+    public function diff(Jalalian $ref): array
+    {
+        if ($this->equalsTo($ref)) {
+            return [0, 0, 0];
+        }
+
+        $biggerDate = $this->greaterThan($ref) ? $this : $ref;
+        $biggerYear = $biggerDate->getYear();
+        $biggerMonth = $biggerDate->getMonth();
+        $biggerDay = $biggerDate->getDay();
+        $smallerDate = $this->greaterThan($ref) ? $ref : $this;
+        $smallerYear = $smallerDate->getYear();
+        $smallerMonth = $smallerDate->getMonth();
+        $smallerDay = $smallerDate->getDay();
+
+        $yearDiff = $biggerYear - $smallerYear;
+        $monthDiff = $biggerMonth - $smallerMonth;
+        $dayDiff = $biggerDay - $smallerDay;
+        if ($dayDiff < 0) {
+            $dayDiff = $biggerDay +
+                $smallerDate->getEndDayOfMonth()->getDay() - $smallerDate->getDay();
+            $monthDiff--;
+        }
+        if ($monthDiff < 0) {
+            $monthDiff += 12;
+            $yearDiff--;
+        }
+
+        return [$yearDiff, $monthDiff, $dayDiff];
+    }
+
+    /**
+     * @param string $dayName One of: شنبه, یکشنبه, دوشنبه, سهشنبه, چهارشنبه, پنجشنبه, جمعه
+     * @return Jalalian
+     */
+    public function next(string $dayName): Jalalian
+    {
+        return $this->fromCarbon($this->toCarbon()->next($this->toCarbonDayName($dayName)));
+    }
+
+    /**
+     * @param string $dayName One of: شنبه, یکشنبه, دوشنبه, سهشنبه, چهارشنبه, پنجشنبه, جمعه
+     * @return Jalalian
+     */
+    public function previous(string $dayName): Jalalian
+    {
+        return $this->fromCarbon($this->toCarbon()->previous($this->toCarbonDayName($dayName)));
+    }
+}
diff --git a/src/Miladr/Jalali/JalaliServiceProvider.php b/src/Miladr/Jalali/JalaliServiceProvider.php
deleted file mode 100644
index d56eafc..0000000
--- a/src/Miladr/Jalali/JalaliServiceProvider.php
+++ /dev/null
@@ -1,64 +0,0 @@
-package('miladr/jalali');
-  }
- 
-  /**
-   * Register the service provider.
-   *
-   * @return void
-   */
-  public function register()
-  {
-      $this->app['jalali'] = $this->app->share(function($app)
-  		{
-  		  return new jDate;
-	});
-      $this->app->booting(function()
-      {
-          $loader = \Illuminate\Foundation\AliasLoader::getInstance();
-          $loader->alias('jDate', 'Miladr\Jalali\jDate');
-	});
-	
-      $this->app['jDateTime'] = $this->app->share(function($app)
-  		{
-  		  return new jDateTime;
-	});
-      $this->app->booting(function()
-      {
-          $loader = \Illuminate\Foundation\AliasLoader::getInstance();
-          $loader->alias('jDateTime', 'Miladr\Jalali\jDateTime');
-	});
-
-
-  }
- 
-  /**
-   * Get the services provided by the provider.
-   *
-   * @return array
-   */
-  public function provides()
-  {
-    return array('jalali','jDateTime');
-  }
-
-}
diff --git a/src/Miladr/Jalali/jDate.php b/src/Miladr/Jalali/jDate.php
deleted file mode 100644
index 6fc081f..0000000
--- a/src/Miladr/Jalali/jDate.php
+++ /dev/null
@@ -1,140 +0,0 @@
-
- *
- *
- * Based on Laravel-Date bundle
- * by Scott Travis 
- * http://github.com/swt83/laravel-date
- *
- * 
- * @package     jDate
- * @author      Sallar Kaboli 
- * @link        http://
- * @basedon     http://github.com/swt83/laravel-date
- * @license     MIT License
- */
-
-class jDate
-{
-	protected $time;
-
-	protected $formats = array(
-		'datetime' => '%Y-%m-%d %H:%M:%S',
-		'date'     => '%Y-%m-%d',
-		'time'     => '%H:%M:%S',
-	);
-
-	public static function forge($str = null)
-	{
-		$class = __CLASS__;
-		return new $class($str);
-	}
-
-	public function __construct($str = null)
-	{
-		if ($str === null){
-			$this->time = time();
-		}
-		else
-		{
-			if (is_numeric($str)){
-				$this->time = $str;
-			}
-			else
-			{
-				$time = strtotime($str);
-
-				if (!$time){
-					$this->time = false;
-				}
-				else{
-					$this->time = $time;
-				}
-			}
-		}
-	}
-
-	public function time()
-	{
-		return $this->time;
-	}
-
-	public function format($str)
-	{
-		// convert alias string
-		if (in_array($str, array_keys($this->formats))){
-			$str = $this->formats[$str];
-		}
-
-		// if valid unix timestamp...
-		if ($this->time !== false){
-			return jDateTime::strftime($str, $this->time);
-		}
-		else{
-			return false;
-		}
-	}
-
-	public function reforge($str)
-	{
-		if ($this->time !== false)
-		{
-			// amend the time
-			$time = strtotime($str, $this->time);
-
-			// if conversion fails...
-			if (!$time){
-				// set time as false
-				$this->time = false;
-			}
-			else{
-				// accept time value
-				$this->time = $time;
-			}
-		}
-
-		return $this;
-	}
-
-	public function ago()
-	{
-		$now = time();
-		$time = $this->time();
-
-		// catch error
-		if (!$time) return false;
-
-		// build period and length arrays
-		$periods = array('ثانیه', 'دقیقه', 'ساعت', 'روز', 'هفته', 'ماه', 'سال', 'قرن');
-		$lengths = array(60, 60, 24, 7, 4.35, 12, 10);
-
-		// get difference
-		$difference = $now - $time;
-
-		// set descriptor
-		if ($difference < 0)
-		{
-			$difference = abs($difference); // absolute value
-			$negative = true;
-		}
-
-		// do math
-		for($j = 0; $difference >= $lengths[$j] and $j < count($lengths)-1; $j++){
-			$difference /= $lengths[$j];
-		}
-
-		// round difference
-		$difference = intval(round($difference));
-
-		// return
-		return number_format($difference).' '.$periods[$j].' '.(isset($negative) ? '' : 'پیش');
-	}
-
-	public function until()
-	{
-		return $this->ago();
-	}
-}
\ No newline at end of file
diff --git a/src/Miladr/Jalali/jDateTime.php b/src/Miladr/Jalali/jDateTime.php
deleted file mode 100644
index 640c596..0000000
--- a/src/Miladr/Jalali/jDateTime.php
+++ /dev/null
@@ -1,574 +0,0 @@
-= 5.2
- *
- * PHP's default 'date' function does not support years higher than
- * 2038. Intorduced in PHP5, DateTime class supports higher years
- * and also invalid date entries.
- * Also, Persian users are using classic 'jdate' function for years now
- * and beside the fact that it's amazing and also helped me to write this
- * one, it's really out of date, and can't be used in modern real world
- * web applications as it is completely written in functions.
- *
- * Copyright (C) 2012  Sallar Kaboli (http://sallar.me)
- * Part of Phoenix Framework (p5x.org) by Phoenix Alternatvie
- *
- * Original Jalali to Gregorian (and vice versa) convertor:
- * Copyright (C) 2000  Roozbeh Pournader and Mohammad Toossi
- *
- * List of supported timezones can be found here:
- * http://www.php.net/manual/en/timezones.php
- *
- * PHP version 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt.  If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @package    jDateTime
- * @author     Sallar Kaboli 
- * @author     Omid Pilevar 
- * @copyright  2003-2012 Sallar Kaboli
- * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
- * @link       http://sallar.me/projects/jdatetime/
- * @see        DateTime
- * @version    2.0.0
- */
-class jDateTime
-{
-
-    /**
-     * Defaults
-     */
-    private static $jalali = true; //Use Jalali Date, If set to false, falls back to gregorian
-    private static $convert = true; //Convert numbers to Farsi characters in utf-8
-    private static $timezone = null; //Timezone String e.g Asia/Tehran, Defaults to Server Timezone Settings
-    private static $temp = array();
-
-    /**
-     * jDateTime::Constructor
-     *
-     * Pass these parameteres when creating a new instance
-     * of this Class, and they will be used as defaults.
-     * e.g $obj = new jDateTime(false, true, 'Asia/Tehran');
-     * To use system defaults pass null for each one or just
-     * create the object without any parameters.
-     *
-     * @author Sallar Kaboli
-     * @param $convert bool Converts numbers to Farsi
-     * @param $jalali bool Converts date to Jalali
-     * @param $timezone string Timezone string
-     */
-    public function __construct($convert = null, $jalali = null, $timezone = null)
-    {
-        if ( $jalali   !== null ) self::$jalali = ($jalali === false) ? false : true;
-        if ( $convert  !== null ) self::$convert = ($convert === false) ? false : true;
-        if ( $timezone !== null ) self::$timezone = ($timezone != null) ? $timezone : null;
-    }
-
-    /**
-     * jDateTime::Date
-     *
-     * Formats and returns given timestamp just like php's
-     * built in date() function.
-     * e.g:
-     * $obj->date("Y-m-d H:i", time());
-     * $obj->date("Y-m-d", time(), false, false, 'America/New_York');
-     *
-     * @author Sallar Kaboli
-     * @param $format string Acceps format string based on: php.net/date
-     * @param $stamp int Unix Timestamp (Epoch Time)
-     * @param $convert bool (Optional) forces convert action. pass null to use system default
-     * @param $jalali bool (Optional) forces jalali conversion. pass null to use system default
-     * @param $timezone string (Optional) forces a different timezone. pass null to use system default
-     * @return string Formatted input
-     */
-    public static function date($format, $stamp = false, $convert = null, $jalali = null, $timezone = null)
-    {
-        //Timestamp + Timezone
-        $stamp    = ($stamp != false) ? $stamp : time();
-        $timezone = ($timezone != null) ? $timezone : ((self::$timezone != null) ? self::$timezone : date_default_timezone_get());
-        $obj      = new \DateTime('@' . $stamp);
-        $obj->setTimezone(new \DateTimeZone($timezone));
-
-        if ( (self::$jalali === false && $jalali === null) || $jalali === false ) {
-            return $obj->format($format);
-        }
-        else {
-            
-            //Find what to replace
-            $chars = (preg_match_all('/([a-zA-Z]{1})/', $format, $chars)) ? $chars[0] : array();
-            
-            //Intact Keys
-            $intact = array('B','h','H','g','G','i','s','I','U','u','Z','O','P');
-            $intact = self::filterArray($chars, $intact);
-            $intactValues = array();
-
-            foreach ($intact as $k => $v) {
-                $intactValues[$k] = $obj->format($v);
-            }
-            //End Intact Keys
-
-
-            //Changed Keys
-            list($year, $month, $day) = array($obj->format('Y'), $obj->format('n'), $obj->format('j'));
-            list($jyear, $jmonth, $jday) = self::toJalali($year, $month, $day);
-
-            $keys = array('d','D','j','l','N','S','w','z','W','F','m','M','n','t','L','o','Y','y','a','A','c','r','e','T');
-            $keys = self::filterArray($chars, $keys, array('z'));
-            $values = array();
-
-            foreach ($keys as $k => $key) {
-
-                $v = '';
-                switch ($key) {
-                    //Day
-                    case 'd':
-                        $v = sprintf("%02d", $jday);
-                        break;
-                    case 'D':
-                        $v = self::getDayNames($obj->format('D'), true);
-                        break;
-                    case 'j':
-                        $v = $jday;
-                        break;
-                    case 'l':
-                        $v = self::getDayNames($obj->format('l'));
-                        break;
-                    case 'N':
-                        $v = self::getDayNames($obj->format('l'), false, 1, true);
-                        break;
-                    case 'S':
-                        $v = 'ام';
-                        break;
-                    case 'w':
-                        $v = self::getDayNames($obj->format('l'), false, 1, true) - 1;
-                        break;
-                    case 'z':
-                        if ($jmonth > 6) {
-                            $v = 186 + (($jmonth - 6 - 1) * 30) + $jday;
-                        }
-                        else {
-                            $v = (($jmonth - 1) * 31) + $jday;
-                        }
-                        self::$temp['z'] = $v;
-                        break;
-                    //Week
-                    case 'W':
-                        $v = is_int(self::$temp['z'] / 7) ? (self::$temp['z'] / 7) : intval(self::$temp['z'] / 7 + 1);
-                        break;
-                    //Month
-                    case 'F':
-                        $v = self::getMonthNames($jmonth);
-                        break;
-                    case 'm':
-                        $v = sprintf("%02d", $jmonth);
-                        break;
-                    case 'M':
-                        $v = self::getMonthNames($jmonth, true);
-                        break;
-                    case 'n':
-                        $v = $jmonth;
-                        break;
-                    case 't':
-                        $v = ( $jmonth == 12 ) ? 29 : ( ($jmonth > 6 && $jmonth != 12) ? 30 : 31 );
-                        break;
-                    //Year
-                    case 'L':
-                        $tmpObj = new \DateTime('@'.(time()-31536000));
-                        $v = $tmpObj->format('L');
-                        break;
-                    case 'o':
-                    case 'Y':
-                        $v = $jyear;
-                        break;
-                    case 'y':
-                        $v = $jyear % 100;
-                        break;
-                    //Time
-                    case 'a':
-                        $v = ($obj->format('a') == 'am') ? 'ق.ظ' : 'ب.ظ';
-                        break;
-                    case 'A':
-                        $v = ($obj->format('A') == 'AM') ? 'قبل از ظهر' : 'بعد از ظهر';
-                        break;
-                    //Full Dates
-                    case 'c':
-                        $v  = $jyear.'-'.sprintf("%02d", $jmonth).'-'.sprintf("%02d", $jday).'T';
-                        $v .= $obj->format('H').':'.$obj->format('i').':'.$obj->format('s').$obj->format('P');
-                        break;
-                    case 'r':
-                        $v  = self::getDayNames($obj->format('D'), true).', '.sprintf("%02d", $jday).' '.self::getMonthNames($jmonth, true);
-                        $v .= ' '.$jyear.' '.$obj->format('H').':'.$obj->format('i').':'.$obj->format('s').' '.$obj->format('P');
-                        break;
-                    //Timezone
-                    case 'e':
-                        $v = $obj->format('e');
-                        break;
-                    case 'T':
-                        $v = $obj->format('T');
-                        break;
-
-                }
-                $values[$k] = $v;
-
-            }
-            //End Changed Keys
-
-            //Merge
-            $keys = array_merge($intact, $keys);
-            $values = array_merge($intactValues, $values);
-
-            //Return
-            $ret = strtr($format, array_combine($keys, $values));
-            return
-            ($convert === false ||
-                ($convert === null && self::$convert === false) ||
-                ( $jalali === false || $jalali === null && self::$jalali === false ))
-                ? $ret : self::convertNumbers($ret);
-
-        }
-
-    }
-
-    /**
-     * jDateTime::gDate
-     *
-     * Same as jDateTime::Date method
-     * but this one works as a helper and returns Gregorian Date
-     * in case someone doesn't like to pass all those false arguments
-     * to Date method.
-     *
-     * e.g. $obj->gDate("Y-m-d") //Outputs: 2011-05-05
-     *      $obj->date("Y-m-d", false, false, false); //Outputs: 2011-05-05
-     *      Both return the exact same result.
-     *
-     * @author Sallar Kaboli
-     * @param $format string Acceps format string based on: php.net/date
-     * @param $stamp int Unix Timestamp (Epoch Time)
-     * @param $timezone string (Optional) forces a different timezone. pass null to use system default
-     * @return string Formatted input
-     */
-    public static function gDate($format, $stamp = false, $timezone = null)
-    {
-        return self::date($format, $stamp, false, false, $timezone);
-    }
-    
-    /**
-     * jDateTime::Strftime
-     *
-     * Format a local time/date according to locale settings
-     * built in strftime() function.
-     * e.g:
-     * $obj->strftime("%x %H", time());
-     * $obj->strftime("%H", time(), false, false, 'America/New_York');
-     *
-     * @author Omid Pilevar
-     * @param $format string Acceps format string based on: php.net/date
-     * @param $stamp int Unix Timestamp (Epoch Time)
-     * @param $jalali bool (Optional) forces jalali conversion. pass null to use system default
-     * @param $timezone string (Optional) forces a different timezone. pass null to use system default
-     * @return string Formatted input
-     */
-    public static function strftime($format, $stamp = false, $jalali = null, $timezone = null)
-    {
-        $str_format_code = array(
-            "%a", "%A", "%d", "%e", "%j", "%u", "%w",
-            "%U", "%V", "%W",
-            "%b", "%B", "%h", "%m",
-            "%C", "%g", "%G", "%y", "%Y",
-            "%H", "%I", "%l", "%M", "%p", "%P", "%r", "%R", "%S", "%T", "%X", "%z", "%Z",
-            "%c", "%D", "%F", "%s", "%x",
-            "%n", "%t", "%%"
-        );
-        
-        $date_format_code = array(
-            "D", "l", "d", "j", "z", "N", "w",
-            "W", "W", "W",
-            "M", "F", "M", "m",
-            "y", "y", "y", "y", "Y",
-            "H", "h", "g", "i", "A", "a", "h:i:s A", "H:i", "s", "H:i:s", "h:i:s", "H", "H",
-            "D j M H:i:s", "d/m/y", "Y-m-d", "U", "d/m/y",
-            "\n", "\t", "%"
-        );
-
-        //Change Strftime format to Date format
-        $format = str_replace($str_format_code, $date_format_code, $format);
-
-        //Convert to date
-        return self::date($format, $stamp, $jalali, $timezone);
-    }
-
-   /**
-     * jDateTime::Mktime
-     *
-     * Creates a Unix Timestamp (Epoch Time) based on given parameters
-     * works like php's built in mktime() function.
-     * e.g:
-     * $time = $obj->mktime(0,0,0,2,10,1368);
-     * $obj->date("Y-m-d", $time); //Format and Display
-     * $obj->date("Y-m-d", $time, false, false); //Display in Gregorian !
-     *
-     * You can force gregorian mktime if system default is jalali and you
-     * need to create a timestamp based on gregorian date
-     * $time2 = $obj->mktime(0,0,0,12,23,1989, false);
-     *
-     * @author Sallar Kaboli
-     * @param $hour int Hour based on 24 hour system
-     * @param $minute int Minutes
-     * @param $second int Seconds
-     * @param $month int Month Number
-     * @param $day int Day Number
-     * @param $year int Four-digit Year number eg. 1390
-     * @param $jalali bool (Optional) pass false if you want to input gregorian time
-     * @param $timezone string (Optional) acceps an optional timezone if you want one
-     * @return int Unix Timestamp (Epoch Time)
-     */
-    public static function mktime($hour, $minute, $second, $month, $day, $year, $jalali = null, $timezone = null)
-    {
-        //Defaults
-        $month = (intval($month) == 0) ? self::date('m') : $month;
-        $day   = (intval($day)   == 0) ? self::date('d') : $day;
-        $year  = (intval($year)  == 0) ? self::date('Y') : $year;
-
-        //Convert to Gregorian if necessary
-        if ( $jalali === true || ($jalali === null && self::$jalali === true) ) {
-            list($year, $month, $day) = self::toGregorian($year, $month, $day);
-        }
-
-        //Create a new object and set the timezone if available
-        $date = $year.'-'.sprintf("%02d", $month).'-'.sprintf("%02d", $day).' '.$hour.':'.$minute.':'.$second;
-
-        if ( self::$timezone != null || $timezone != null ) {
-            $obj = new \DateTime($date, new \DateTimeZone(($timezone != null) ? $timezone : self::$timezone));
-        }
-        else {
-            $obj = new \DateTime($date);
-        }
-
-        //Return
-        return $obj->format("U");
-    }
-    
-    /**
-     * jDateTime::Checkdate
-     *
-     * Checks the validity of the date formed by the arguments.
-     * A date is considered valid if each parameter is properly defined.
-     * works like php's built in checkdate() function.
-     * Leap years are taken into consideration.
-     * e.g:
-     * $obj->checkdate(10, 21, 1390); // Return true
-     * $obj->checkdate(9, 31, 1390);  // Return false
-     *
-     * You can force gregorian checkdate if system default is jalali and you
-     * need to check based on gregorian date
-     * $check = $obj->checkdate(12, 31, 2011, false);
-     *
-     * @author Omid Pilevar
-     * @param $month int The month is between 1 and 12 inclusive.
-     * @param $day int The day is within the allowed number of days for the given month.
-     * @param $year int The year is between 1 and 32767 inclusive.
-     * @param $jalali bool (Optional) pass false if you want to input gregorian time
-     * @return bool
-     */
-    public static function checkdate($month, $day, $year, $jalali = null)
-    {
-        //Defaults
-        $month = (intval($month) == 0) ? self::date('n') : intval($month);
-        $day   = (intval($day)   == 0) ? self::date('j') : intval($day);
-        $year  = (intval($year)  == 0) ? self::date('Y') : intval($year);
-        
-        //Check if its jalali date
-        if ( $jalali === true || ($jalali === null && self::$jalali === true) )
-        {
-            $epoch = self::mktime(0, 0, 0, $month, $day, $year);
-            
-            if( self::date("Y-n-j", $epoch,false) == "$year-$month-$day" ) {
-                $ret = true;
-            }
-            else{
-                $ret = false; 
-            }
-        }
-        else //Gregorian Date
-        { 
-            $ret = checkdate($month, $day, $year);
-        }
-        
-        //Return
-        return $ret;
-    }
-
-    /**
-     * System Helpers below
-     *
-     */
-    private static function filterArray($needle, $heystack, $always = array())
-    {
-        foreach($heystack as $k => $v)
-        {
-            if( !in_array($v, $needle) && !in_array($v, $always) )
-                unset($heystack[$k]);
-        }
-        
-        return $heystack;
-    }
-    
-    private static function getDayNames($day, $shorten = false, $len = 1, $numeric = false)
-    {
-        $ret = '';
-        switch ( strtolower($day) ) {
-            case 'sat': case 'saturday': $ret = 'شنبه'; $n = 1; break;
-            case 'sun': case 'sunday': $ret = 'یکشنبه'; $n = 2; break;
-            case 'mon': case 'monday': $ret = 'دوشنبه'; $n = 3; break;
-            case 'tue': case 'tuesday': $ret = 'سه شنبه'; $n = 4; break;
-            case 'wed': case 'wednesday': $ret = 'چهارشنبه'; $n = 5; break;
-            case 'thu': case 'thursday': $ret = 'پنجشنبه'; $n = 6; break;
-            case 'fri': case 'friday': $ret = 'جمعه'; $n = 7; break;
-        }
-        return ($numeric) ? $n : (($shorten) ? mb_substr($ret, 0, $len, 'UTF-8') : $ret);
-    }
-
-    private static function getMonthNames($month, $shorten = false, $len = 3)
-    {
-        $ret = '';
-        switch ( $month ) {
-            case '1': $ret = 'فروردین'; break;
-            case '2': $ret = 'اردیبهشت'; break;
-            case '3': $ret = 'خرداد'; break;
-            case '4': $ret = 'تیر'; break;
-            case '5': $ret = 'امرداد'; break;
-            case '6': $ret = 'شهریور'; break;
-            case '7': $ret = 'مهر'; break;
-            case '8': $ret = 'آبان'; break;
-            case '9': $ret = 'آذر'; break;
-            case '10': $ret = 'دی'; break;
-            case '11': $ret = 'بهمن'; break;
-            case '12': $ret = 'اسفند'; break;
-        }
-        return ($shorten) ? mb_substr($ret, 0, $len, 'UTF-8') : $ret;
-    }
-
-    private static function convertNumbers($matches)
-    {
-        $farsi_array = array("۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹");
-        $english_array = array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
-        return str_replace($english_array, $farsi_array, $matches);
-    }
-
-    private static function div($a, $b)
-    {
-        return (int) ($a / $b);
-    }
-
-    /**
-     * Gregorian to Jalali Conversion
-     * Copyright (C) 2000  Roozbeh Pournader and Mohammad Toossi
-     *
-     */
-    public static function toJalali($g_y, $g_m, $g_d)
-    {
-
-        $g_days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
-        $j_days_in_month = array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);
-
-        $gy = $g_y-1600;
-        $gm = $g_m-1;
-        $gd = $g_d-1;
-
-        $g_day_no = 365*$gy+self::div($gy+3, 4)-self::div($gy+99, 100)+self::div($gy+399, 400);
-
-        for ($i=0; $i < $gm; ++$i)
-            $g_day_no += $g_days_in_month[$i];
-        if ($gm>1 && (($gy%4==0 && $gy%100!=0) || ($gy%400==0)))
-            $g_day_no++;
-        $g_day_no += $gd;
-
-        $j_day_no = $g_day_no-79;
-
-        $j_np = self::div($j_day_no, 12053);
-        $j_day_no = $j_day_no % 12053;
-
-        $jy = 979+33*$j_np+4*self::div($j_day_no, 1461);
-
-        $j_day_no %= 1461;
-
-        if ($j_day_no >= 366) {
-            $jy += self::div($j_day_no-1, 365);
-            $j_day_no = ($j_day_no-1)%365;
-        }
-
-        for ($i = 0; $i < 11 && $j_day_no >= $j_days_in_month[$i]; ++$i)
-            $j_day_no -= $j_days_in_month[$i];
-        $jm = $i+1;
-        $jd = $j_day_no+1;
-
-        return array($jy, $jm, $jd);
-
-    }
-
-    /**
-     * Jalali to Gregorian Conversion
-     * Copyright (C) 2000  Roozbeh Pournader and Mohammad Toossi
-     *
-     */
-    public static function toGregorian($j_y, $j_m, $j_d)
-    {
-
-        $g_days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
-        $j_days_in_month = array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);
-
-        $jy = $j_y-979;
-        $jm = $j_m-1;
-        $jd = $j_d-1;
-
-        $j_day_no = 365*$jy + self::div($jy, 33)*8 + self::div($jy%33+3, 4);
-        for ($i=0; $i < $jm; ++$i)
-            $j_day_no += $j_days_in_month[$i];
-
-        $j_day_no += $jd;
-
-        $g_day_no = $j_day_no+79;
-
-        $gy = 1600 + 400*self::div($g_day_no, 146097);
-        $g_day_no = $g_day_no % 146097;
-
-        $leap = true;
-        if ($g_day_no >= 36525) {
-            $g_day_no--;
-            $gy += 100*self::div($g_day_no,  36524);
-            $g_day_no = $g_day_no % 36524;
-
-            if ($g_day_no >= 365)
-                $g_day_no++;
-            else
-                $leap = false;
-        }
-
-        $gy += 4*self::div($g_day_no, 1461);
-        $g_day_no %= 1461;
-
-        if ($g_day_no >= 366) {
-            $leap = false;
-
-            $g_day_no--;
-            $gy += self::div($g_day_no, 365);
-            $g_day_no = $g_day_no % 365;
-        }
-
-        for ($i = 0; $g_day_no >= $g_days_in_month[$i] + ($i == 1 && $leap); $i++)
-            $g_day_no -= $g_days_in_month[$i] + ($i == 1 && $leap);
-        $gm = $i+1;
-        $gd = $g_day_no+1;
-
-        return array($gy, $gm, $gd);
-
-    }
-
-}
diff --git a/src/helpers.php b/src/helpers.php
new file mode 100644
index 0000000..7cfb212
--- /dev/null
+++ b/src/helpers.php
@@ -0,0 +1,13 @@
+assertTrue(CalendarUtils::checkDate(1391, 2, 30, true));
+        $this->assertFalse(CalendarUtils::checkDate(1395, 13, 10, true));
+        $this->assertFalse(CalendarUtils::checkDate(1395, 12, 31, true));
+        $this->assertFalse(CalendarUtils::checkDate(2015, 12, 31, true));
+    }
+
+    public function testToJalali()
+    {
+        $this->assertTrue(CalendarUtils::toJalali(2016, 5, 7) === [1395, 2, 18]);
+        $this->assertFalse(CalendarUtils::toJalali(2015, 5, 7) === [1394, 2, 18]);
+    }
+
+    public function testToGregorian()
+    {
+        $this->assertTrue(CalendarUtils::toGregorian(1395, 2, 18) === [2016, 5, 7]);
+        $this->assertFalse(CalendarUtils::toGregorian(1394, 2, 18) === [2015, 5, 7]);
+    }
+
+    public function testIsLeapJalaliYear()
+    {
+        $this->assertTrue(CalendarUtils::isLeapJalaliYear(1395));
+        $this->assertFalse(CalendarUtils::isLeapJalaliYear(1394));
+    }
+
+    public function testStrftime()
+    {
+        $table = [
+            [
+                '2016-05-08',
+                'Y-m-d',
+                '1395-02-19'
+            ],
+            [
+                '2022-03-24',
+                'y-m-d',
+                '01-01-04'
+            ],
+            [
+                '2023-03-24',
+                'y-m-D',
+                '02-01-ج'
+            ],
+        ];
+
+        foreach ($table as $row) {
+            list($dateTimeString, $format, $expected) = $row;
+            $timestamp = strtotime($dateTimeString);
+            $this->assertEquals($expected, CalendarUtils::strftime($format, $timestamp));
+        }
+    }
+
+    public function testFormatMonthName()
+    {
+        $months = range(1, 12);
+
+        // Should returns iranian months name as default
+        foreach ($months as $month) {
+            $date = sprintf('1401/%d/10', $month);
+            $actual = Jalalian::fromFormat('Y/n/d', $date)->format('F');
+            $expected = CalendarUtils::IRANIAN_MONTHS_NAME[$month - 1];
+            $this->assertEquals($expected, $actual);
+        }
+
+        // Should returns afghan months name when set
+        CalendarUtils::useAfghanMonthsName();
+        foreach ($months as $month) {
+            $date = sprintf('1401/%d/10', $month);
+            $actual = Jalalian::fromFormat('Y/n/d', $date)->format('F');
+            $expected = CalendarUtils::AFGHAN_MONTHS_NAME[$month - 1];
+            $this->assertEquals($expected, $actual);
+        }
+
+        // Should returns afghan months name when set
+        CalendarUtils::useIranianMonthsName();
+        foreach ($months as $month) {
+            $date = sprintf('1401/%d/10', $month);
+            $actual = Jalalian::fromFormat('Y/n/d', $date)->format('F');
+            $expected = CalendarUtils::IRANIAN_MONTHS_NAME[$month - 1];
+            $this->assertEquals($expected, $actual);
+        }
+    }
+
+    public function test_parseFromPersian()
+    {
+        $jalaliDate = '1393/03/27';
+        $date = CalendarUtils::parseFromFormat('Y/m/d', $jalaliDate);
+
+        $this->assertEquals(1393, $date['year']);
+        $this->assertEquals(03, $date['month']);
+        $this->assertEquals(27, $date['day']);
+
+        $date = CalendarUtils::parseFromFormat('Y-m-d H:i:s', '1395-03-15 21:00:00');
+        $this->assertEquals(21, $date['hour']);
+        $this->assertEquals(0, $date['minute']);
+        $this->assertEquals(0, $date['second']);
+    }
+
+    public function testCreateDateTimeFormFormat()
+    {
+        $jdate = '1394/11/25 15:00:00';
+        $gDateTime = CalendarUtils::createDatetimeFromFormat('Y/m/d H:i:s', $jdate);
+
+        $this->assertTrue($gDateTime instanceof \DateTime);
+
+        $this->assertTrue('2016-02-14 15:00:00' === $gDateTime->format('Y-m-d H:i:s'));
+    }
+
+    public function testCreateCarbonFormFormat()
+    {
+        $jdate = '1394/11/25 15:00:00';
+        $carbon = CalendarUtils::createCarbonFromFormat('Y/m/d H:i:s', $jdate);
+
+        $this->assertTrue($carbon instanceof \Carbon\Carbon);
+        $this->assertTrue($carbon->day === 14);
+        $this->assertTrue('2016-02-14 15:00:00' === $carbon->format('Y-m-d H:i:s'));
+
+        $jalaiDateFormatted = Jalalian::fromDateTime($carbon->toDateString())->format('Y-m-d H:i:s');
+        $jalaiDateTimeFormatted = Jalalian::fromDateTime($carbon->toDateTimeString())->format('Y-m-d H:i:s');
+        $this->assertFalse($jalaiDateFormatted === '1394-11-25 15:00:00');
+        $this->assertTrue($jalaiDateTimeFormatted === '1394-11-25 15:00:00');
+
+        // Test support years after 1416
+        $carbon = CalendarUtils::createCarbonFromFormat('Y/m/d', '1417/10/11');
+        $this->assertEquals('2039-01-01', $carbon->format('Y-m-d'));
+    }
+
+    public function testTimezone()
+    {
+        date_default_timezone_set('Asia/Tehran');
+        $tehranDate = Jalalian::now();
+        $tehranHour = $tehranDate->format('H');
+        $tehranMin = $tehranDate->format('i');
+
+        date_default_timezone_set('UTC');
+        $utcDate = Jalalian::now();
+        $utcHour = $utcDate->format('H');
+        $utcMin = $utcDate->format('i');
+
+        $tzOffset = $this->getTimeZoneOffset('Asia/Tehran', 'UTC');
+
+        $this->assertTrue((((($utcHour * 60) + $utcMin) * 60) - ((($tehranHour * 60) + $tehranMin) * 60)) === $tzOffset);
+    }
+
+
+    private function getTimeZoneOffset($remote_tz, $origin_tz = null)
+    {
+        if ($origin_tz === null) {
+            if (!is_string($origin_tz = date_default_timezone_get())) {
+                return false; // A UTC timestamp was returned -- bail out!
+            }
+        }
+        $origin_dtz = new DateTimeZone($origin_tz);
+        $remote_dtz = new DateTimeZone($remote_tz);
+        $origin_dt = new DateTime("now", $origin_dtz);
+        $remote_dt = new DateTime("now", $remote_dtz);
+        $offset = $origin_dtz->getOffset($origin_dt) - $remote_dtz->getOffset($remote_dt);
+
+        return $offset;
+    }
+}
diff --git a/tests/HelperTest.php b/tests/HelperTest.php
new file mode 100644
index 0000000..7570373
--- /dev/null
+++ b/tests/HelperTest.php
@@ -0,0 +1,17 @@
+assertTrue(function_exists('jdate'));
+
+        $jdate = jdate('now');
+        $this->assertTrue($jdate instanceof Jalalian);
+    }
+}
diff --git a/tests/JalalianTest.php b/tests/JalalianTest.php
new file mode 100644
index 0000000..3c22047
--- /dev/null
+++ b/tests/JalalianTest.php
@@ -0,0 +1,441 @@
+assertTrue($jDate instanceof Jalalian);
+        $this->assertEquals($jDate->getDay(), 25);
+        $this->assertEquals($jDate->getYear(), 1397);
+        $this->assertEquals($jDate->getMonth(), 1);
+
+        $this->assertEquals($jDate->format('Y-m-d H:i:s'), '1397-01-25 00:00:00');
+    }
+
+    public function testGetDayOfYear()
+    {
+        $jDate = new Jalalian(1397, 1, 25);
+        $this->assertEquals($jDate->getDayOfYear(), 25);
+
+        $jDate = new Jalalian(1397, 5, 20);
+        $this->assertEquals($jDate->getDayOfYear(), 144);
+
+        $jDate = new Jalalian(1397, 7, 3);
+        $this->assertEquals($jDate->getDayOfYear(), 189);
+
+        $jDate = new Jalalian(1397, 12, 29);
+        $this->assertEquals($jDate->getDayOfYear(), 365);
+
+        $jDate = new Jalalian(1395, 12, 30);
+        $this->assertTrue($jDate->isLeapYear());
+        $this->assertEquals($jDate->getDayOfYear(), 366);
+    }
+
+    public function testModifiers()
+    {
+        $jDate = new Jalalian(1397, 1, 18);
+
+        $this->assertEquals($jDate->addYears()->getYear(), 1398);
+        $this->assertEquals($jDate->addMonths(11)->getMonth(), 12);
+        $this->assertEquals($jDate->addMonths(11)->addDays(20)->getMonth(), 1);
+        $this->assertEquals($jDate->subDays(8)->getNextMonth()->getMonth(), 2);
+
+        $jDate = Jalalian::fromCarbon(Carbon::createFromDate(2019, 1, 1));
+        $this->assertEquals($jDate->addMonths(4)->getYear(), 1398);
+
+        $jDate = new Jalalian(1397, 1, 31);
+        $this->assertEquals($jDate->addMonths(1)->getDay(), 31);
+        $this->assertEquals($jDate->addYears(3)->getDay(), 31);
+        $this->assertEquals($jDate->addMonths(36)->toString(), $jDate->addYears(3)->toString());
+        $this->assertEquals($jDate->subYears(10)->toString(), (new Jalalian(1387, 1, 31))->toString());
+        $this->assertTrue($jDate->subYears(2)->subMonths(34)->equalsTo(new Jalalian(1392, 03, 31)));
+
+        $jDate = (new Jalalian(1397, 6, 11))->subMonths(1);
+        $this->assertEquals($jDate->getMonth(), 5);
+
+        $this->assertEquals((new Jalalian(1397, 7, 1))->subMonths(1)->getMonth(), 6);
+
+        $jDate = Jalalian::now();
+        $month = $jDate->getMonth();
+        if ($month > 1) {
+            $this->assertEquals($month - 1, $jDate->subMonths()->getMonth());
+        }
+
+
+        $jDate = Jalalian::fromFormat('Y-m-d', '1397-12-12');
+        $this->assertEquals('1398-01-12', $jDate->addMonths(1)->format('Y-m-d'));
+
+        $jDate = Jalalian::fromFormat('Y-m-d', '1397-11-30');
+        $this->assertEquals('1397-12-29', $jDate->addMonths(1)->format('Y-m-d'));
+
+        $jDate = Jalalian::fromFormat('Y-m-d', '1397-06-30');
+        $this->assertEquals('1397-07-30', $jDate->addMonths(1)->format('Y-m-d'));
+
+        $jDate = Jalalian::fromFormat('Y-m-d', '1397-06-31');
+        $this->assertEquals('1397-07-30', $jDate->addMonths(1)->format('Y-m-d'));
+
+        $jDate = Jalalian::fromFormat('Y-m-d', '1395-12-30');
+        $this->assertEquals('1399-12-30', $jDate->addMonths(48)->format('Y-m-d'));
+
+        $jDate = Jalalian::fromFormat('Y-m-d', '1395-12-30');
+        $this->assertEquals('1398-12-29', $jDate->addMonths(36)->format('Y-m-d'));
+    }
+
+    public function testForge()
+    {
+        $jDate = Jalalian::forge(strtotime('now'));
+        $this->assertTrue($jDate instanceof Jalalian);
+        $this->assertTrue($jDate->getTimestamp() === strtotime('now'));
+
+        $jDate = Jalalian::forge(1333857600);
+        $this->assertEquals($jDate->toString(), '1391-01-20 04:00:00');
+
+        $jDate = Jalalian::forge('last monday');
+        $this->assertTrue($jDate instanceof Jalalian);
+
+        $jDate = Jalalian::forge(1552608000);
+        $this->assertEquals('1397-12-24', $jDate->format('Y-m-d'));
+    }
+
+    public function testMaximumYearFormatting()
+    {
+        $jDate = Jalalian::fromFormat('Y-m-d', '1800-12-01');
+        $this->assertEquals(1800, $jDate->getYear());
+        $this->assertEquals($jDate->format('Y-m-d'), '1800-12-01');
+
+        // issue-110
+        $jDate = Jalalian::fromFormat('Y-m-d', '1416-12-01');
+        $this->assertEquals(1416, $jDate->format('Y'));
+    }
+
+    public function testGetWeekOfMonth()
+    {
+        $jDate = new Jalalian(1400, 1, 8);
+        $this->assertEquals($jDate->getWeekOfMonth(), 2);
+
+        $jDate = new Jalalian(1400, 5, 13);
+        $this->assertEquals($jDate->getWeekOfMonth(), 3);
+
+        $jDate = new Jalalian(1390, 11, 11);
+        $this->assertEquals($jDate->getWeekOfMonth(), 2);
+
+        $jDate = new Jalalian(1395, 7, 20);
+        $this->assertEquals($jDate->getWeekOfMonth(), 4);
+
+        $jDate = new Jalalian(1401, 1, 5);
+        $this->assertEquals($jDate->getWeekOfMonth(), 1);
+
+        $jDate = new Jalalian(1390, 8, 7);
+        $this->assertEquals($jDate->getWeekOfMonth(), 2);
+
+
+        $jDate = new Jalalian(1390, 8, 27);
+        $this->assertEquals($jDate->getWeekOfMonth(), 4);
+
+        $jDate = new Jalalian(1390, 7, 1);
+        $this->assertEquals($jDate->getWeekOfMonth(), 1);
+
+        $jDate = new Jalalian(1390, 7, 2);
+        $this->assertEquals($jDate->getWeekOfMonth(), 2);
+
+        $jDate = new Jalalian(1390, 7, 30);
+        $this->assertEquals($jDate->getWeekOfMonth(), 6);
+
+        $jDate = new Jalalian(1390, 6, 15);
+        $this->assertEquals($jDate->getWeekOfMonth(), 3);
+
+        $jDate = new Jalalian(1390, 6, 25);
+        $this->assertEquals($jDate->getWeekOfMonth(), 4);
+
+        $jDate = new Jalalian(1390, 6, 26);
+        $this->assertEquals($jDate->getWeekOfMonth(), 5);
+
+        $jDate = new Jalalian(1401, 3, 7);
+        $this->assertEquals($jDate->getWeekOfMonth(), 2);
+    }
+
+    public function testGetFirstDayOfWeek()
+    {
+        $jDate = new Jalalian(1401, 1, 23);
+        $this->assertEquals($jDate->getFirstDayOfWeek()->format('Y-m-d'), '1401-01-20');
+
+        $jDate = new Jalalian(1395, 4, 24);
+        $this->assertEquals($jDate->getFirstDayOfWeek()->format('Y-m-d'), '1395-04-19');
+
+        $jDate = new Jalalian(1398, 11, 7);
+        $this->assertEquals($jDate->getFirstDayOfWeek()->format('Y-m-d'), '1398-11-05');
+
+        $jDate = new Jalalian(1400, 8, 19);
+        $this->assertEquals($jDate->getFirstDayOfWeek()->format('Y-m-d'), '1400-08-15');
+    }
+
+    public function testGetFirstDayOfMonth()
+    {
+        $jDate = new Jalalian(1401, 1, 23);
+        $this->assertEquals($jDate->getFirstDayOfMonth()->format('Y-m-d'), '1401-01-01');
+
+        $jDate = new Jalalian(1390, 5, 14);
+        $this->assertEquals($jDate->getFirstDayOfMonth()->format('Y-m-d'), '1390-05-01');
+
+        $jDate = new Jalalian(1399, 2, 29);
+        $this->assertEquals($jDate->getFirstDayOfMonth()->format('Y-m-d'), '1399-02-01');
+
+        $jDate = new Jalalian(1398, 10, 10);
+        $this->assertEquals($jDate->getFirstDayOfMonth()->format('Y-m-d'), '1398-10-01');
+    }
+
+    public function testGetFirstDayOfYear()
+    {
+        $jDate = new Jalalian(1401, 6, 11);
+        $this->assertEquals($jDate->getFirstDayOfYear()->format('Y-m-d'), '1401-01-01');
+
+        $jDate = new Jalalian(1399, 11, 28);
+        $this->assertEquals($jDate->getFirstDayOfYear()->format('Y-m-d'), '1399-01-01');
+
+        $jDate = new Jalalian(1394, 1, 12);
+        $this->assertEquals($jDate->getFirstDayOfYear()->format('Y-m-d'), '1394-01-01');
+
+        $jDate = new Jalalian(1393, 9, 5);
+        $this->assertEquals($jDate->getFirstDayOfYear()->format('Y-m-d'), '1393-01-01');
+    }
+
+    public function testAddDay()
+    {
+        $jDate = new Jalalian(1401, 6, 31);
+        $this->assertEquals($jDate->addDay()->format('Y-m-d'), '1401-07-01');
+    }
+
+    public function testSubDay()
+    {
+        $jDate = new Jalalian(1401, 6, 1);
+        $this->assertEquals($jDate->subDay()->format('Y-m-d'), '1401-05-31');
+    }
+
+    public function testGetLastWeek()
+    {
+        $jDate = new Jalalian(1401, 6, 8);
+        $this->assertEquals($jDate->getLastWeek()->format('Y-m-d'), '1401-06-01');
+    }
+
+    public function testGetLastMonth()
+    {
+        $jDate = new Jalalian(1401, 6, 8);
+        $this->assertEquals($jDate->getLastMonth()->format('Y-m-d'), '1401-05-08');
+    }
+
+    public function testGetFirstDayOfQuarter()
+    {
+        $jDate = new Jalalian(1402, 1, 25);
+        $this->assertEquals('1402-01-01', $jDate->getFirstDayOfQuarter()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 2, 25);
+        $this->assertEquals('1402-01-01', $jDate->getFirstDayOfQuarter()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 3, 25);
+        $this->assertEquals('1402-01-01', $jDate->getFirstDayOfQuarter()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 4, 25);
+        $this->assertEquals('1402-04-01', $jDate->getFirstDayOfQuarter()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 5, 25);
+        $this->assertEquals('1402-04-01', $jDate->getFirstDayOfQuarter()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 6, 25);
+        $this->assertEquals('1402-04-01', $jDate->getFirstDayOfQuarter()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 7, 25);
+        $this->assertEquals('1402-07-01', $jDate->getFirstDayOfQuarter()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 8, 25);
+        $this->assertEquals('1402-07-01', $jDate->getFirstDayOfQuarter()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 9, 25);
+        $this->assertEquals('1402-07-01', $jDate->getFirstDayOfQuarter()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 10, 25);
+        $this->assertEquals('1402-10-01', $jDate->getFirstDayOfQuarter()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 11, 19);
+        $this->assertEquals('1402-10-01', $jDate->getFirstDayOfQuarter()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 12, 25);
+        $this->assertEquals('1402-10-01', $jDate->getFirstDayOfQuarter()->format('Y-m-d'));
+
+    }
+
+    public function testGetEndDayOfWeek()
+    {
+        /*
+         *  --------------------------------
+         *       Day 1402 (March 2024)
+         *  --------------------------------
+         *    Sat Sun Mon Tue Wed Thu Fri
+         *  --------------------------------
+         *                             1
+         *     2   3   4   5   6   7   8
+         *     9  10  11  12  13  14  15
+         *    16  17  18  19  20  21  22
+         *    23  24  25  26  27  28  29
+         *    30
+         *  -------------------------------
+         */
+
+        $jDate = new Jalalian(1402, 10, 25);
+        $this->assertEquals('1402-10-29', $jDate->getEndDayOfWeek()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 10, 29);
+        $this->assertEquals('1402-10-29', $jDate->getEndDayOfWeek()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 10, 23);
+        $this->assertEquals('1402-10-29', $jDate->getEndDayOfWeek()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 12, 29);
+        $this->assertEquals('1403-01-03', $jDate->getEndDayOfWeek()->format('Y-m-d'));
+
+    }
+
+    public function testGetEndDayOfMonth()
+    {
+        /*
+         *  --------------------------------
+         *       Day 1402 (March 2024)
+         *  --------------------------------
+         *    Sat Sun Mon Tue Wed Thu Fri
+         *  --------------------------------
+         *                             1
+         *     2   3   4   5   6   7   8
+         *     9  10  11  12  13  14  15
+         *    16  17  18  19  20  21  22
+         *    23  24  25  26  27  28  29
+         *    30
+         *  -------------------------------
+         */
+
+        $jDate = new Jalalian(1402, 10, 25);
+        $this->assertEquals('1402-10-30', $jDate->getEndDayOfMonth()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 04, 12);
+        $this->assertEquals('1402-04-31', $jDate->getEndDayOfMonth()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 12, 25);
+        $this->assertEquals('1402-12-29', $jDate->getEndDayOfMonth()->format('Y-m-d'));
+    }
+
+    public function testGetEndDayOfYear()
+    {
+        $jDate = new Jalalian(1402, 10, 25);
+        $this->assertEquals('1402-12-29', $jDate->getEndDayOfYear()->format('Y-m-d'));
+
+        // LeapYear
+        $jDate = new Jalalian(1403, 10, 25);
+        $this->assertEquals('1403-12-30', $jDate->getEndDayOfYear()->format('Y-m-d'));
+    }
+
+    public function testGetEndDayOfQuarter()
+    {
+        $jDate = new Jalalian(1402, 10, 25);
+        $this->assertEquals('1402-12-29', $jDate->getEndDayOfQuarter()->format('Y-m-d'));
+
+        $jDate = new Jalalian(1402, 2, 25);
+        $this->assertEquals('1402-03-31', $jDate->getEndDayOfQuarter()->format('Y-m-d'));
+
+
+        $jDate = new Jalalian(1402, 6, 01);
+        $this->assertEquals('1402-06-31', $jDate->getEndDayOfQuarter()->format('Y-m-d'));
+
+
+        $jDate = new Jalalian(1402, 9, 01);
+        $this->assertEquals('1402-09-30', $jDate->getEndDayOfQuarter()->format('Y-m-d'));
+    }
+
+    public function testGetQuarter()
+    {
+        $jDate = new Jalalian(1402, 10, 25);
+        $this->assertEquals(4, $jDate->getQuarter());
+
+        $jDate = new Jalalian(1402, 1, 01);
+        $this->assertEquals(1, $jDate->getQuarter());
+
+
+        $jDate = new Jalalian(1402, 05, 24);
+        $this->assertEquals(2, $jDate->getQuarter());
+
+        $jDate = new Jalalian(1402, 7, 23);
+        $this->assertEquals(3, $jDate->getQuarter());
+    }
+
+    public function testdiff()
+    {
+        $jDate = new Jalalian(1401, 6, 26);
+
+        //same day
+        $this->assertEquals($jDate->diff(new Jalalian(1401, 6, 26)), [0, 0, 0]);
+
+        //year before
+        $this->assertEquals($jDate->diff(new Jalalian(1401, 6, 25)), [0, 0, 1]);
+
+        //day after
+        $this->assertEquals($jDate->diff(new Jalalian(1401, 6, 27)), [0, 0, 1]);
+
+        //same montt, same year, before
+        $this->assertEquals($jDate->diff(new Jalalian(1401, 6, 24)), [0, 0, 2]);
+
+        //same month, same year, after
+        $this->assertEquals($jDate->diff(new Jalalian(1401, 6, 28)), [0, 0, 2]);
+
+        //same year, before, smaller day
+        $this->assertEquals($jDate->diff(new Jalalian(1401, 4, 12)), [0, 2, 14]);
+
+        //same year, before, greater day
+        $this->assertEquals($jDate->diff(new Jalalian(1401, 4, 27)), [0, 1, 30]);
+
+        //same year, after, smaller day
+        $this->assertEquals($jDate->diff(new Jalalian(1401, 9, 10)), [0, 2, 15]);
+
+        //same year, after, greater day
+        $this->assertEquals($jDate->diff(new Jalalian(1401, 10, 28)), [0, 4, 2]);
+
+        //previous year, smaller month, smaller day
+        $this->assertEquals($jDate->diff(new Jalalian(1389, 4, 12)), [12, 2, 14]);
+
+        //previous year, smaller month, greater day
+        $this->assertEquals($jDate->diff(new Jalalian(1395, 4, 29)), [6, 1, 28]);
+
+        //previous year, greater month, smaller day
+        $this->assertEquals($jDate->diff(new Jalalian(1395, 9, 10)), [5, 9, 16]);
+
+        //previous year, greater month, greater day
+        $this->assertEquals($jDate->diff(new Jalalian(1395, 9, 30)), [5, 8, 26]);
+
+        //greater year, smaller month, smaller day
+        $this->assertEquals($jDate->diff(new Jalalian(1402, 4, 12)), [0, 9, 17]);
+
+        //greater year, smaller month, greater day
+        $this->assertEquals($jDate->diff(new Jalalian(1403, 4, 29)), [1, 10, 3]);
+
+        //greater year, greater month, smaller day
+        $this->assertEquals($jDate->diff(new Jalalian(1405, 9, 10)), [4, 2, 15]);
+
+        //greater year, greater month, greater day
+        $this->assertEquals($jDate->diff(new Jalalian(1405, 9, 30)), [4, 3, 4]);
+    }
+
+    public function testNext()
+    {
+        $jDate = new Jalalian(1403, 05, 28);
+        $this->assertEquals('1403-05-30', $jDate->next('سهشنبه')->format('Y-m-d'));
+    }
+
+    public function testPrevious()
+    {
+        $jDate = new Jalalian(1403, 05, 28);
+        $this->assertEquals('1403-05-22', $jDate->previous('دوشنبه')->format('Y-m-d'));
+    }
+}