├── IntlDateClass.php ├── tests ├── bootstrap.php └── IntlDateTest.php ├── phpunit.xml ├── composer.json ├── .travis.yml ├── LICENSE ├── README.md └── IntlDateTrait.php /IntlDateClass.php: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | ./tests 11 | 12 | 13 | 14 | 15 | ./IntlDateTrait.php 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meysampg/intldate", 3 | "description": "A small php library for date converting between multiple calendar", 4 | "type": "library", 5 | "keywords": ["date","extension","jalali","intl","buddhist","chinese","coptic","ethiopic","gregorian","hebrew","indian","islamic","islamic-civil","japanese","persian","taiwan"], 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Meysam P.G.", 10 | "email": "p.g.meysam@gmail.com" 11 | } 12 | ], 13 | "require": { 14 | "ext-intl" : "*" 15 | }, 16 | "autoload": { 17 | "psr-4": { 18 | "meysampg\\intldate\\": "" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | env: 2 | global: 3 | - CC_TEST_REPORTER_ID=40141fbf49a6c6d471733121626ae3f4cdfd7eda064141a1c01cdd2816504541 4 | - GIT_COMMITTED_AT=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then git log -1 --pretty=format:%ct; else git log -1 --skip 1 --pretty=format:%ct; fi) 5 | 6 | language: php 7 | 8 | php: 9 | - 7.0 10 | 11 | before_script: 12 | - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter 13 | - chmod +x ./cc-test-reporter 14 | - if [ $(phpenv version-name) = "7.0" ]; then ./cc-test-reporter before-build; fi 15 | 16 | install: 17 | - composer install 18 | 19 | script: 20 | - phpunit --coverage-clover clover.xml 21 | 22 | after_script: 23 | - if [ $(phpenv version-name) = "7.0" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT; fi 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Meysam GanJi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/IntlDateTest.php: -------------------------------------------------------------------------------- 1 | intldate; 11 | 12 | $now = 1499057157; // Monday, July 3, 2017 4:45:57 AM 13 | $expected = '2017/07/03, 04:45:57'; 14 | $actual = $intldate->fromTimestamp($now)->toGregorian()->asDateTime(); 15 | 16 | $this->assertEquals($expected, $actual); 17 | } 18 | 19 | public function testItShouldGetAnTimestampAndReturnTruePersianDateTime() 20 | { 21 | $intldate = $this->intldate; 22 | 23 | $now = 1499057157; // Monday, July 3, 2017 4:45:57 AM 24 | $expected = '1396/04/12, 04:45:57'; 25 | $actual = $intldate->fromTimestamp($now)->toPersian('en')->asDateTime(); 26 | 27 | $this->assertEquals($expected, $actual); 28 | } 29 | 30 | public function testItShouldGetAnTimezonedTimestampAndReturnTruePersianDateTime() 31 | { 32 | $intldate = $this->intldate; 33 | 34 | $now = 1499073357; // Monday, July 3, 2017 9:15:57 AM 35 | $tz = 'Asia/Tehran'; 36 | $expected = '1396/04/12, 04:45:57'; 37 | $actual = $intldate->fromTimestamp($now, $tz)->toPersian('en')->asDateTime(); 38 | 39 | $this->assertEquals($expected, $actual); 40 | } 41 | 42 | public function testItShouldGetAnTimestampAndReturnTruePersianTimezonedDateTime() 43 | { 44 | $intldate = $this->intldate; 45 | 46 | $now = 1499057157; // Monday, July 3, 2017 4:45:57 AM 47 | $tz = 'Asia/Tehran'; 48 | $expected = '1396/04/12, 09:15:57'; 49 | $actual = $intldate->fromTimestamp($now)->toPersian('en', $tz)->asDateTime(); 50 | 51 | $this->assertEquals($expected, $actual); 52 | } 53 | 54 | public function testItShouldGetAnGregorianDateTimeAndReturnTrueTimestamp() 55 | { 56 | $intldate = $this->intldate; 57 | 58 | $now = [2017, 07, 03, 04, 45, 57]; 59 | $expected = 1499057157; // Monday, July 3, 2017 4:45:57 AM 60 | $actual = $intldate->fromGregorian($now)->asTimestamp(); 61 | 62 | $this->assertEquals($expected, $actual); 63 | } 64 | 65 | public function testItShouldGetAnPersianDateTimeAndReturnTrueTimestamp() 66 | { 67 | $intldate = $this->intldate; 68 | 69 | $now = [1396, 04, 12, 04, 45, 57]; 70 | $expected = 1499057157; // Monday, July 3, 2017 4:45:57 AM 71 | $actual = $intldate->fromPersian($now)->asTimestamp(); 72 | 73 | $this->assertEquals($expected, $actual); 74 | } 75 | 76 | public function testItShouldGetAnGregorianDateTimeAndReturnATimezonedPersianDateTime() 77 | { 78 | $intldate = $this->intldate; 79 | 80 | $now = [2017, 07, 03, 04, 45, 57]; 81 | $expected = '1396/04/12, 09:15:57'; 82 | $tz = 'Asia/Tehran'; 83 | $actual = $intldate->fromGregorian($now)->toPersian('en', $tz)->asDateTime(); 84 | 85 | $this->assertEquals($expected, $actual); 86 | } 87 | 88 | public function testItShouldGetAnTimezonedGregorianDateTimeAndReturnAPersianDateTime() 89 | { 90 | $intldate = $this->intldate; 91 | 92 | $now = [2017, 07, 03, 9, 15, 57]; 93 | $expected = '1396/04/12, 04:45:57'; 94 | $tz = 'Asia/Tehran'; 95 | $actual = $intldate->fromGregorian($now, 'en', $tz)->toPersian('en')->asDateTime(); 96 | 97 | $this->assertEquals($expected, $actual); 98 | } 99 | 100 | public function testItShouldGetAnTimezonedGregorianDateTimeAndReturnATimezonedPersianDateTime() 101 | { 102 | $intldate = $this->intldate; 103 | 104 | $now = [2017, 07, 03, 7, 15, 57]; 105 | $expected = '1396/04/12, 04:45:57'; 106 | $fromTz = 'Asia/Tehran'; 107 | $toTz = 'Europe/Amsterdam'; 108 | $actual = $intldate->fromGregorian($now, 'en', $fromTz)->toPersian('en', $toTz)->asDateTime(); 109 | 110 | $this->assertEquals($expected, $actual); 111 | } 112 | 113 | public function testItShouldGetAnTimezonedGregorianDateTimeAndReturnALocalePersianDateTime() 114 | { 115 | $intldate = $this->intldate; 116 | 117 | $now = [2017, 07, 03, 9, 15, 57]; 118 | $expected = '۱۳۹۶/۰۴/۱۲, ۰۴:۴۵:۵۷'; 119 | $tz = 'Asia/Tehran'; 120 | $actual = $intldate->fromGregorian($now, 'en', $tz)->toPersian('fa')->asDateTime(); 121 | 122 | $this->assertEquals($expected, $actual); 123 | } 124 | 125 | public function testItShouldGetADatetimeStringAndSplitItIntoAnArrayOfThatDatetimeString() 126 | { 127 | $intldate = $this->intldate; 128 | 129 | $given = '2016/01/22 11:43:24'; 130 | $expected = [ 131 | 0 => 2016, 132 | 1 => 0, 133 | 2 => 22, 134 | 3 => 11, 135 | 4 => 43, 136 | 5 => 24, 137 | ]; 138 | $result = $intldate->guessDateTime($given); 139 | $this->assertEquals($expected, $result); 140 | 141 | $given = '2017/04/23 13:42:11'; 142 | $expected = [ 143 | 0 => 2017, 144 | 1 => 3, 145 | 2 => 23, 146 | 3 => 13, 147 | 4 => 42, 148 | 5 => 11, 149 | ]; 150 | $result = $intldate->guessDateTime($given); 151 | $this->assertEquals($expected, $result); 152 | } 153 | 154 | public function testItShoudReturnMinusOneWhenInvalidMonthIsGiven() 155 | { 156 | $intldate = $this->intldate; 157 | 158 | $given = '2016/00/22 11:43:24'; 159 | $result = $intldate->guessDateTime($given); 160 | $this->assertFalse($result); 161 | 162 | $given = '2016/14/22 11:43:24'; 163 | $result = $intldate->guessDateTime($given); 164 | $this->assertFalse($result); 165 | } 166 | 167 | public function testItShoudReturnMinusOneWhenInvalidDayIsGiven() 168 | { 169 | $intldate = $this->intldate; 170 | 171 | $given = '2016/01/0 11:43:24'; 172 | $result = $intldate->guessDateTime($given); 173 | $this->assertFalse($result); 174 | 175 | $given = '2016/04/33 11:43:24'; 176 | $result = $intldate->guessDateTime($given); 177 | $this->assertFalse($result); 178 | } 179 | 180 | public function testItShoudReturnMinusOneWhenInvalidHourIsGiven() 181 | { 182 | $intldate = $this->intldate; 183 | 184 | $given = '2016/01/1 -1:43:24'; 185 | $result = $intldate->guessDateTime($given); 186 | $this->assertFalse($result); 187 | 188 | $given = '2016/04/12 25:43:24'; 189 | $result = $intldate->guessDateTime($given); 190 | $this->assertFalse($result); 191 | } 192 | 193 | public function testItShoudReturnMinusOneWhenInvalidMinuteIsGiven() 194 | { 195 | $intldate = $this->intldate; 196 | 197 | $given = '2016/01/1 2:-1:24'; 198 | $result = $intldate->guessDateTime($given); 199 | $this->assertFalse($result); 200 | 201 | $given = '2016/04/12 12:61:24'; 202 | $result = $intldate->guessDateTime($given); 203 | $this->assertFalse($result); 204 | } 205 | 206 | public function testItShoudReturnMinusOneWhenInvalidSecondIsGiven() 207 | { 208 | $intldate = $this->intldate; 209 | 210 | $given = '2016/01/1 12:43:-2'; 211 | $result = $intldate->guessDateTime($given); 212 | $this->assertFalse($result); 213 | 214 | $given = '2016/04/12 15:43:62'; 215 | $result = $intldate->guessDateTime($given); 216 | $this->assertFalse($result); 217 | } 218 | 219 | protected function setUp() 220 | { 221 | parent::setUp(); 222 | 223 | $this->intldate = $this->getMockForTrait('meysampg\intldate\IntlDateTrait'); 224 | } 225 | 226 | protected function tearDown() 227 | { 228 | parent::tearDown(); 229 | 230 | $this->intldate = null; 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Intl. Date 2 | ========== 3 | 🟥⚠️ _THIS PACKAGE IS ABANDONED. PLEASE USE https://github.com/mahdyar/intldate OR FORK THIS REPOSITORY AND MAINTENANCE IT FOR YOURSELF_ ⚠️🟥 4 | 5 | [![StyleCI](https://styleci.io/repos/67480531/shield?branch=master)](https://styleci.io/repos/67480531) [![Build Status](https://travis-ci.org/meysampg/intldate.svg?branch=master)](https://travis-ci.org/meysampg/intldate) [![Total Downloads](https://poser.pugx.org/meysampg/intldate/downloads)](https://packagist.org/packages/meysampg/intldate) [![Latest Stable Version](https://poser.pugx.org/meysampg/intldate/v/stable)](https://packagist.org/packages/meysampg/intldate) [![Maintainability](https://api.codeclimate.com/v1/badges/a8958ec9f4ffc059b6fb/maintainability)](https://codeclimate.com/github/meysampg/intldate/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/a8958ec9f4ffc059b6fb/test_coverage)](https://codeclimate.com/github/meysampg/intldate/test_coverage) 6 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmeysampg%2Fintldate.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fmeysampg%2Fintldate?ref=badge_shield) 7 | 8 | PHP Library for Converting Date to Multiple Calendars 9 | 10 | Installation 11 | ------------ 12 | 13 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 14 | 15 | Either run 16 | 17 | ```bash 18 | composer require --prefer-dist meysampg/intldate "*" 19 | ``` 20 | 21 | or add 22 | 23 | ```json 24 | "meysampg/intldate": "*" 25 | ``` 26 | 27 | to the require section of your `composer.json` file. 28 | 29 | Also easily you can [Download](https://github.com/meysampg/intldate/archive/master.zip) and use it. 30 | 31 | Usage 32 | ----- 33 | 34 | Once the library is installed, simply use it in your php file: 35 | 36 | ```php 37 | use meysampg\intldate\IntlDateTrait; 38 | ``` 39 | and use it on your desired class: 40 | 41 | ```php 42 | fromGregorian([2017, 9, 7, 12, 23, 45])->toPersian('en')->asDateTime(); 54 | } 55 | ``` 56 | 57 | Anathomy 58 | -------- 59 | 60 | `IntlDateTrait` has a simple logic for naming methods: "A date starts from *origin* and ends to *final*. So all methods (setters and getters) that are related to incoming date are named by `setOriginXXXX` and `getOriginXXXX` (which `XXXX` shows a feature of time, like *timezone* or *locale*) and all methods that are corresponded to outgoing date are regarded as `setFinalXXXX` and `getFinalXXXX`. A list of available methods can be find in bottom of this document. 61 | 62 | Conversion 63 | ---------- 64 | At first I must note that incoming date must be an array in this form: 65 | 66 | ```php 67 | [ 68 | year, // 2016 69 | month, // 2 70 | day, // 23 71 | hour, // 12 72 | minute, // 23 73 | second // 4 74 | ] 75 | ``` 76 | Currently, the library **CAN'T** parse a string as time (See ToDo section), so before converting a date, you **MUST** parse it on a acceptable array (It can be done with `preg_match` or each tools that you know). Now you can easily use 77 | `IntlDateTrait::from($datetimeArray, $locale, $calendar)` for importing an incoming date and `IntlDateTrait::to($locale, $calendar)` for converting it to another system. We disccuesed about `$datetimeArray` in the first of this section, it's our date for converting on a accepted format. `$locale` is the regional information of a language. For example for The *English* it's `en`, for *Farsi* it's `fa`, for *Spanish* it's `es` and so on. You can find a complete list of them at [this link](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes). And finally calendar is your desired date system. This library use the `Intl*` family of `php` and so you can use all supported calendar in `ICU` project. Now this calendars are supported: 78 | - persian 79 | - gregorian 80 | - japanese 81 | - buddhist 82 | - chinese 83 | - indian 84 | - islamic 85 | - hebrew 86 | - coptic 87 | - ethiopic 88 | 89 | It's better to use their handler in code instead of using direct name. These handlers are: 90 | 91 | ```php 92 | // Use them in `self::$CAL_CALENDAR, for example `$calendar = self::$CAL_HEBREW`. 93 | $CAL_PERSIAN 94 | $CAL_JAPANESE 95 | $CAL_BUDDHIST 96 | $CAL_CHINESE 97 | $CAL_INDIAN 98 | $CAL_ISLAMIC 99 | $CAL_HEBREW 100 | $CAL_COPTIC 101 | $CAL_ETHIOPIC 102 | $CAL_GREGORIAN 103 | ``` 104 | 105 | ShortHands 106 | ---------- 107 | There are some shorthands for converting dates in a painless way (Yeah! With all of my proud, I'm a **Lazy** man :D). This shorthands are formatted as `fromYyyy()` for incoming date function and `toZzzz()` for outgoing date function such that, `Yyyy` and `Zzzz` are the name of calendars. For incoming function, the signature is `fromYyyy($datetimeArray, $locale = 'en_US', $timezone = 'UTC)` and for outgoing is `toZzzz($locale = 'fa', $timezone = 'UTC')`. Use `$locale` in incoming function if you have non-latin digits and use it on outgoing function, if you wanna show the converted date by latin digits (Based on region of calendar, `$locales` are defined, for example the default locate of `Persian` calendar for outgoing function is `fa`). Also with changing `$timezone` in both `fromYyyy` and `ToZzzz` functions, you can convert a datetime from one to another. Shorthands are listed in table. 108 | 109 | | Incoming | Outgoing | 110 | |---------------|---------------| 111 | |fromPersian | toPersian | 112 | |fromJapanese |toJapanese | 113 | |fromBuddhist |toBuddhist | 114 | |fromChinese |toChinese | 115 | |fromIndian |toIndian | 116 | |fromIslamic |toIslamic | 117 | |fromHebrew |toHebrew | 118 | |fromCoptic |toCoptic | 119 | |fromEthiopic |toEthiopic | 120 | |fromGregorian |toGregorian | 121 | 122 | Showing Date 123 | ------------ 124 | There are two functions for showing converted dates. The first is `asDateTime` and the last one is `asTimestamp`. 125 | 126 | Signature of `asDateTime` is `asDateTime($pattern = 'yyyy/MM/dd, HH:mm:ss')`. This function accepts an `ICU`-acceptable format. You can find more info from [this link](http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details). Also it's good idea for implementing a function that parse traditional php `date`-acceptable format (See ToDo section). 127 | 128 | `asTimestamp` function return the unix epoch, positive integer for time after that and negative integer for before that. 129 | 130 | Examples 131 | -------- 132 | There are some examples for using `IntlDateTrait`. I think they are necessary and sufficent. 133 | 134 | ```php 135 | $this->fromTimestamp(1504770825)->toPersian('en')->asDateTime(); 136 | // '1396/06/16, 07:53:45' 137 | 138 | $this->fromGregorian([2017, 9, 7, 12, 23, 45])->toPersian('en')->asDateTime(); 139 | // '1396/06/16, 07:53:45' 140 | 141 | $this->fromGregorian([2017, 9, 7, 12, 23, 45])->toPersian()->asDateTime(); 142 | // '۱۳۹۶/۰۶/۱۶, ۰۷:۵۳:۴۵' 143 | 144 | $this->fromGregorian([2017, 9, 7, 12, 23, 45])->toJapanese()->asDateTime(); 145 | // '0029/09/07, 07:53:45' 146 | 147 | $this->fromGregorian([2017, 9, 7, 12, 23, 45])->toIslamic()->asDateTime(); 148 | // '١٤٣٨/١٢/١٧, ٠٧:٥٣:٤٥' 149 | 150 | $this->fromGregorian([2017, 9, 7, 12, 23, 45])->toBuddhist()->asDateTime(); 151 | // '2560/09/07, 07:53:45' 152 | 153 | $this->fromGregorian([2017, 9, 7, 12, 23, 45])->toChinese()->asDateTime(); 154 | // '0034/07/17, 07:53:45' 155 | 156 | $this->fromGregorian([2017, 9, 7, 12, 23, 45])->toIndian()->asDateTime(); 157 | // '1939/06/16, 07:53:45' 158 | 159 | $this->fromGregorian([2017, 9, 7, 12, 23, 45])->toHebrew()->asDateTime(); 160 | // 'תשע״ז/י״ב/ט״ז, 07:53:45' 161 | 162 | $this->fromGregorian([2017, 9, 7, 12, 23, 45])->toCoptic()->asDateTime(); 163 | // '1733/13/02, 07:53:45' 164 | 165 | $this->fromGregorian([2017, 9, 7, 12, 23, 45])->toEthiopic()->asDateTime(); 166 | // '2009/13/02, 07:53:45' 167 | 168 | $this->fromPersian([1396, 6, 16, 12, 23, 45])->toIslamic()->asDateTime(); 169 | // '١٤٣٨/١٢/١٧, ٠٧:٥٣:٤٥' 170 | 171 | $this->fromPersian([1396, 6, 16, 12, 23, 45])->toGregorian()->asDateTime(); 172 | // '2017/09/07, 07:53:45' 173 | 174 | $this->fromPersian([1396, 6, 16, 12, 23, 45])->toGregorian()->setFinalTimeZone('Asia/Tehran')->asDateTime(); 175 | // '2017/09/07, 12:23:45' 176 | 177 | $this->fromPersian([1396, 6, 16, 12, 23, 45])->toGregorian()->setFinalTimeZone('Asia/Tehran')->asDateTime('yyyy'); 178 | // '2017' 179 | 180 | $this->fromGregorian([2017, 9, 7, 12, 23, 45])->asTimestamp(); 181 | // '1504770825' 182 | 183 | $this->fromPersian([1396, 6, 16, 12, 23, 45])->asTimestamp(); 184 | // '1504770825' 185 | ``` 186 | 187 | IntlDateTrait API 188 | ----------------- 189 | There are some methods that help to control more on converting process. I just list them in this section. I think thier name complain their usages, If it's not, please write document for them :D. 190 | 191 | |Setters |Gettes | 192 | |--------------------------------|--------------------------| 193 | |`setOriginDate($datetimeArray)` | `getFinalDate()` | 194 | |`setFromLocale($locale)` |`getFromLocale()` | 195 | |`setFromCalendar($calendar)` |`getFromCalendar()` | 196 | |`setToLocale($locale)` |`getToLocale()` | 197 | |`setToCalendar($calendar)` |`getToCalendar()` | 198 | |`getFromLocaleAndCalendar()` |`getToLocaleAndCalendar()`| 199 | |`setOriginTimeZone($timezone)` |`getOriginTimeZone()` | 200 | |`setFinalTimeZone($timezone)` |`getFinalTimeZone()` | 201 | |`setOriginCalendar($locale)` |`getOriginCalendar()` | 202 | |`setFinalCalendar($locale)` |`getFinalCalendar()` | 203 | |`setFinalDateType($datetype)` |`getFinalDateType()` | 204 | |`setFinalTimeType($timetype)` |`getFinalTimeType()` | 205 | |`setFinalCalendarType($calendarType)`|`getFinalCalendarType()`| 206 | |`setFinalPattern($pattern)` |`getFinalPattern()` | 207 | |`setIntlDateFormatter($locale = "en_US", $datetype = IntlDateFormatter::FULL, $timetype = IntlDateFormatter::FULL, $timezone = 'UTC', $calendar = IntlDateFormatter::GREGORIAN, $pattern = 'yyyy/MM/dd HH:mm:ss')`|`getIntlDateFormatter()`| 208 | |`setIntlCalendar($timezone = 'Asia/Tehran', $locale = 'fa_IR@calendar=persian')`|`getIntlCalendar()`| 209 | 210 | ToDo 211 | ---- 212 | - Implement `parsePattern($pattern)` method. 213 | 214 | ```php 215 | /** 216 | * Implement a function to parse both ICU patterns and php date 217 | * function patterns and return a pattern that is compatible on 218 | * ICU format. The php pattern must start with php keyword, for 219 | * example `php:Y-F-d, H:i:s` is a php pattern. 220 | */ 221 | ``` 222 | 223 | - ~~Implement `guessDateTime($timestring)` method.~~ 224 | 225 | - ~~Write tests!~~ 226 | 227 | Contribute 228 | ---------- 229 | Just fork this repository, do your modification or addition and send a pull request! 230 | 231 | 232 | ## License 233 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmeysampg%2Fintldate.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fmeysampg%2Fintldate?ref=badge_large) 234 | -------------------------------------------------------------------------------- /IntlDateTrait.php: -------------------------------------------------------------------------------- 1 | 9 | * @license https://github.com/meysampg/intldate/blob/master/LICENSE MIT 10 | * 11 | * @version 1.1 12 | * 13 | * @link https://github.com/meysampg/intldate 14 | */ 15 | 16 | namespace meysampg\intldate; 17 | 18 | use Exception; 19 | use IntlCalendar; 20 | use IntlDateFormatter; 21 | 22 | trait IntlDateTrait 23 | { 24 | private $_fromLocale; 25 | private $_toLocale; 26 | private $_fromCalendar; 27 | private $_toCalendar; 28 | 29 | private $_intlDateFormatter; 30 | private $_intlCalendar; 31 | 32 | public static $CAL_PERSIAN = 'persian'; 33 | public static $CAL_JAPANESE = 'japanese'; 34 | public static $CAL_BUDDHIST = 'buddhist'; 35 | public static $CAL_CHINESE = 'chinese'; 36 | public static $CAL_INDIAN = 'indian'; 37 | public static $CAL_ISLAMIC = 'islamic'; 38 | public static $CAL_HEBREW = 'hebrew'; 39 | public static $CAL_COPTIC = 'coptic'; 40 | public static $CAL_ETHIOPIC = 'ethiopic'; 41 | public static $CAL_GREGORIAN = ''; 42 | 43 | /** 44 | * Return final date and time on supplied format. 45 | * 46 | * @param string $pattern pattern of datetime based on ICU standards 47 | * 48 | * @return string 49 | * 50 | * @since 1.0.0 51 | */ 52 | public function asDateTime($pattern = 'yyyy/MM/dd, HH:mm:ss') 53 | { 54 | $this->setFinalPattern($this->parsePattern($pattern)); 55 | 56 | return $this->getIntlDateFormatter()->format($this->getIntlCalendar()); 57 | } 58 | 59 | /** 60 | * Return final time as a timestamp. 61 | * 62 | * @return int 63 | * 64 | * @since 1.0.0 65 | */ 66 | public function asTimestamp() 67 | { 68 | return $this->getIntlCalendar()->toDateTime()->format('U'); 69 | } 70 | 71 | /** 72 | * Get datetime as a timestamp. 73 | * 74 | * @param int $timestamp timestamp on origin 75 | * 76 | * @return static 77 | * 78 | * @since 1.0.3 79 | */ 80 | public function fromTimestamp($timestamp, $timezone = 'UTC') 81 | { 82 | // [TODO] use DateTime object for parse timestamp 83 | $oldTz = date_default_timezone_get(); 84 | date_default_timezone_set($timezone); 85 | $timestamp = mktime(date('H', $timestamp), date('i', $timestamp), date('s', $timestamp), date('n', $timestamp), date('j', $timestamp), date('Y', $timestamp)); 86 | date_default_timezone_set('UTC'); 87 | $utcDT = gmdate('c', $timestamp); 88 | $dateArray = getdate(strtotime(gmdate('c', $timestamp))); 89 | date_default_timezone_set($oldTz); 90 | unset($dateArray[0]); 91 | 92 | $this->from($dateArray, 'en_US', null, $timezone); 93 | 94 | return $this; 95 | } 96 | 97 | /** 98 | * Get information of datetime on origin. 99 | * 100 | * @param array $datetime Array contains datetime information. Its elements 101 | * are [year, month, day, hour, minute, second]. 102 | * @param string $locale locale for showing datetime on it (e.g. `en_US` or 103 | * `fa_IR`, 'es_US', ...) 104 | * @param string $calendar Calendar on origin 105 | * @param string $timezone Timezone on origin 106 | * 107 | * @return static 108 | * 109 | * @since 1.0.0 110 | */ 111 | public function from( 112 | $datetime = [], 113 | $locale = 'en_US', 114 | $calendar = null, 115 | $timezone = 'UTC' 116 | ) { 117 | $datetime = $this->parseDateTime($datetime); 118 | $calendar = $calendar ?: self::$CAL_GREGORIAN; 119 | 120 | $this->setIntlCalendar() 121 | ->setFromCalendar($calendar)->setFromLocale($locale) 122 | ->setOriginCalendar($this->getFromLocaleAndCalendar()) 123 | ->setOriginTimeZone($timezone) 124 | ->setOriginDate($datetime); 125 | 126 | return $this; 127 | } 128 | 129 | /** 130 | * Convert datetime to a desired calendar. 131 | * 132 | * @param string $locale locale for showing new datetime 133 | * @param mixed $calendar calendar system for showing new datetime 134 | * @param string $timezone timezone of destination 135 | * 136 | * @return static 137 | */ 138 | public function to( 139 | $locale = 'en_US', 140 | $calendar = null, 141 | $timezone = 'UTC' 142 | ) { 143 | $calendar = $calendar !== null ? $calendar : self::$CAL_PERSIAN; 144 | 145 | $this->setIntlDateFormatter() 146 | ->setToCalendar($calendar)->setToLocale($locale) 147 | ->setFinalTimeZone($timezone) 148 | ->setFinalCalendar($this->getToLocaleAndCalendar()); 149 | 150 | if ($calendar == self::$CAL_GREGORIAN) { 151 | $this->setFinalCalendarType(IntlDateFormatter::GREGORIAN); 152 | } else { 153 | $this->setFinalCalendarType(IntlDateFormatter::TRADITIONAL); 154 | } 155 | 156 | return $this; 157 | } 158 | 159 | public function fromPersian($datetime, $locale = 'en_US', $timezone = 'UTC') 160 | { 161 | $this->from($datetime, $locale, self::$CAL_PERSIAN, $timezone); 162 | 163 | return $this; 164 | } 165 | 166 | public function toPersian($locale = 'fa', $timezone = 'UTC') 167 | { 168 | $this->to($locale, self::$CAL_PERSIAN, $timezone); 169 | 170 | return $this; 171 | } 172 | 173 | public function fromJapanese($datetime, $locale = 'en_US', $timezone = 'UTC') 174 | { 175 | $this->from($datetime, $locale, self::$CAL_JAPANESE, $timezone); 176 | 177 | return $this; 178 | } 179 | 180 | public function toJapanese($locale = 'jp', $timezone = 'UTC') 181 | { 182 | $this->to($locale, self::$CAL_JAPANESE, $timezone); 183 | 184 | return $this; 185 | } 186 | 187 | public function fromBuddhist($datetime, $locale = 'en_US', $timezone = 'UTC') 188 | { 189 | $this->from($datetime, $locale, self::$CAL_BUDDHIST, $timezone); 190 | 191 | return $this; 192 | } 193 | 194 | public function toBuddhist($locale = 'th', $timezone = 'UTC') 195 | { 196 | $this->to($locale, self::$CAL_BUDDHIST, $timezone); 197 | 198 | return $this; 199 | } 200 | 201 | public function fromChinese($datetime, $locale = 'en_US', $timezone = 'UTC') 202 | { 203 | $this->from($datetime, $locale, self::$CAL_CHINESE, $timezone); 204 | 205 | return $this; 206 | } 207 | 208 | public function toChinese($locale = 'ch', $timezone = 'UTC') 209 | { 210 | $this->to($locale, self::$CAL_CHINESE, $timezone); 211 | 212 | return $this; 213 | } 214 | 215 | public function fromIndian($datetime, $locale = 'en_US', $timezone = 'UTC') 216 | { 217 | $this->from($datetime, $locale, self::$CAL_INDIAN, $timezone); 218 | 219 | return $this; 220 | } 221 | 222 | public function toIndian($locale = 'hi', $timezone = 'UTC') 223 | { 224 | $this->to($locale, self::$CAL_INDIAN, $timezone = 'UTC', $timezone); 225 | 226 | return $this; 227 | } 228 | 229 | public function fromIslamic($datetime, $locale = 'en_US', $timezone = 'UTC') 230 | { 231 | $this->from($datetime, $locale, self::$CAL_ISLAMIC, $timezone); 232 | 233 | return $this; 234 | } 235 | 236 | public function toIslamic($locale = 'ar', $timezone = 'UTC') 237 | { 238 | $this->to($locale, self::$CAL_ISLAMIC, $timezone); 239 | 240 | return $this; 241 | } 242 | 243 | public function fromHebrew($datetime, $locale = 'en_US', $timezone = 'UTC') 244 | { 245 | $this->from($datetime, $locale, self::$CAL_HEBREW, $timezone); 246 | 247 | return $this; 248 | } 249 | 250 | public function toHebrew($locale = 'he', $timezone = 'UTC') 251 | { 252 | $this->to($locale, self::$CAL_HEBREW, $timezone); 253 | 254 | return $this; 255 | } 256 | 257 | public function fromCoptic($datetime, $locale = 'en_US', $timezone = 'UTC') 258 | { 259 | $this->from($datetime, $locale, self::$CAL_COPTIC, $timezone); 260 | 261 | return $this; 262 | } 263 | 264 | public function toCoptic($locale = 'en_US', $timezone = 'UTC') 265 | { 266 | $this->to($locale, self::$CAL_COPTIC, $timezone); 267 | 268 | return $this; 269 | } 270 | 271 | public function fromEthiopic($datetime, $locale = 'en_US', $timezone = 'UTC') 272 | { 273 | $this->from($datetime, $locale, self::$CAL_ETHIOPIC, $timezone); 274 | 275 | return $this; 276 | } 277 | 278 | public function toEthiopic($locale = 'am', $timezone = 'UTC') 279 | { 280 | $this->to($locale, self::$CAL_ETHIOPIC, $timezone); 281 | 282 | return $this; 283 | } 284 | 285 | public function fromGregorian($datetime, $locale = 'en_US', $timezone = 'UTC') 286 | { 287 | $this->from($datetime, $locale, self::$CAL_GREGORIAN, $timezone); 288 | 289 | return $this; 290 | } 291 | 292 | public function toGregorian($locale = 'en_US', $timezone = 'UTC') 293 | { 294 | $this->to($locale, self::$CAL_GREGORIAN, $timezone); 295 | 296 | return $this; 297 | } 298 | 299 | public function setOriginDate($datetimeArray) 300 | { 301 | $this->getIntlCalendar()->set($datetimeArray[0], $datetimeArray[1], $datetimeArray[2], $datetimeArray[3], $datetimeArray[4], $datetimeArray[5]); 302 | 303 | return $this; 304 | } 305 | 306 | public function getFinalDate() 307 | { 308 | return $this->getIntlDateFormatter()->formatter($this->getIntlCalendar()); 309 | } 310 | 311 | public function setFromLocale($locale) 312 | { 313 | $this->_fromLocale = trim($locale); 314 | 315 | return $this; 316 | } 317 | 318 | public function getFromLocale() 319 | { 320 | return $this->_fromLocale; 321 | } 322 | 323 | public function setFromCalendar($calendar) 324 | { 325 | $this->_fromCalendar = '@calendar='.trim($calendar); 326 | 327 | return $this; 328 | } 329 | 330 | public function getFromCalendar() 331 | { 332 | return $this->_fromCalendar; 333 | } 334 | 335 | public function setToLocale($locale) 336 | { 337 | $this->_toLocale = trim($locale); 338 | 339 | return $this; 340 | } 341 | 342 | public function getToLocale() 343 | { 344 | return $this->_toLocale; 345 | } 346 | 347 | public function setToCalendar($calendar) 348 | { 349 | $this->_toCalendar = '@calendar='.trim($calendar); 350 | 351 | return $this; 352 | } 353 | 354 | public function getToCalendar() 355 | { 356 | return $this->_toCalendar; 357 | } 358 | 359 | public function getFromLocaleAndCalendar() 360 | { 361 | return $this->getFromLocale().$this->getFromCalendar(); 362 | } 363 | 364 | public function getToLocaleAndCalendar() 365 | { 366 | return $this->getToLocale().$this->getToCalendar(); 367 | } 368 | 369 | public function setOriginTimeZone($timezone) 370 | { 371 | $this->getIntlCalendar()->setTimeZone($timezone); 372 | 373 | return $this; 374 | } 375 | 376 | public function getOriginTimeZone() 377 | { 378 | return $this->getIntlCalendar()->getTimeZone(); 379 | } 380 | 381 | public function setFinalTimeZone($timezone) 382 | { 383 | $this->setIntlDateFormatter( 384 | $this->getToLocaleAndCalendar(), 385 | $this->getFinalDateType(), 386 | $this->getFinalTimeType(), 387 | $timezone, 388 | $this->getFinalCalendarType(), 389 | $this->getFinalPattern() 390 | ); 391 | 392 | return $this; 393 | } 394 | 395 | public function getFinalTimeZone() 396 | { 397 | return $this->getIntlDateFormatter()->getTimeZone(); 398 | } 399 | 400 | public function setOriginCalendar($locale) 401 | { 402 | $this->setIntlCalendar( 403 | $this->getOriginTimeZone(), 404 | $locale 405 | ); 406 | 407 | return $this; 408 | } 409 | 410 | public function getOriginCalendar() 411 | { 412 | return $this->getIntlCalendar()->getLocale(); 413 | } 414 | 415 | public function setFinalCalendar($locale) 416 | { 417 | $this->setIntlDateFormatter( 418 | $locale, 419 | $this->getFinalDateType(), 420 | $this->getFinalTimeType(), 421 | $this->getFinalTimeZone(), 422 | $this->getFinalCalendarType(), 423 | $this->getFinalPattern(), 424 | true 425 | ); 426 | 427 | return $this; 428 | } 429 | 430 | public function getFinalCalendar() 431 | { 432 | return $this->getIntlDateFormatter()->getLocale(); 433 | } 434 | 435 | public function setFinalDateType($datetype) 436 | { 437 | $this->setIntlDateFormatter( 438 | $this->getToLocaleAndCalendar(), 439 | $datetype, 440 | $this->getFinalTimeType(), 441 | $this->getFinalTimeZone(), 442 | $this->getFinalCalendarType(), 443 | $this->getFinalPattern(), 444 | true 445 | ); 446 | 447 | return $this; 448 | } 449 | 450 | public function getFinalDateType() 451 | { 452 | $this->getIntlDateFormatter()->getDateType(); 453 | } 454 | 455 | public function setFinalTimeType($timetype) 456 | { 457 | $this->setIntlDateFormatter( 458 | $this->getToLocaleAndCalendar(), 459 | $this->getFinalDateType(), 460 | $timetype, 461 | $this->getFinalTimeZone(), 462 | $this->getFinalCalendarType(), 463 | $this->getFinalPattern(), 464 | true 465 | ); 466 | 467 | return $this; 468 | } 469 | 470 | public function getFinalTimeType() 471 | { 472 | return $this->getIntlDateFormatter()->getTimeType(); 473 | } 474 | 475 | public function setFinalCalendarType($calendarType) 476 | { 477 | $this->setIntlDateFormatter( 478 | $this->getToLocaleAndCalendar(), 479 | $this->getFinalDateType(), 480 | $this->getFinalTimeType(), 481 | $this->getFinalTimeZone(), 482 | $calendarType, 483 | $this->getFinalPattern(), 484 | true 485 | ); 486 | 487 | return $this; 488 | } 489 | 490 | public function getFinalCalendarType() 491 | { 492 | return $this->getIntlDateFormatter()->getCalendar(); 493 | } 494 | 495 | public function setFinalPattern($pattern) 496 | { 497 | $this->getIntlDateFormatter()->setPattern($pattern); 498 | 499 | return $this; 500 | } 501 | 502 | public function getFinalPattern() 503 | { 504 | return $this->getIntlDateFormatter()->getPattern(); 505 | } 506 | 507 | // [TODO] 508 | public function parsePattern($pattern) 509 | { 510 | /* 511 | * Implement a function to parse both ICU patterns and php date 512 | * function patterns and return a pattern that is compatible on 513 | * ICU format. The php pattern must start with php keyword, for 514 | * example `php:Y-F-d, H:i:s` is a php pattern. 515 | */ 516 | return $pattern; 517 | } 518 | 519 | /** 520 | * This method gets a datetime string as the input and converts it 521 | * into a standard array. 522 | * Example: '2016/01/22 11:43:24' 523 | * to an array like: 524 | * [ 525 | * 0 => 2016, // Year 526 | * 1 => 0, // Month. IntlCalendar use 0 for first month and so on. 527 | * 2 => 22, // Day 528 | * 3 => 11, // Hour 529 | * 4 => 43, // Minute 530 | * 5 => 24, // Seconds 531 | *] 532 | * Returns False if invalid month, day, hour, minute, or second is given. 533 | */ 534 | public function guessDateTime($timestring) 535 | { 536 | $date_time = explode(' ', $timestring); 537 | 538 | $date = explode('/', $date_time[0]); 539 | $time = explode(':', $date_time[1]); 540 | 541 | $year = (int) $date[0]; 542 | $month = $date[1]; 543 | $day = (int) $date[2]; 544 | $hour = (int) $time[0]; 545 | $minute = (int) $time[1]; 546 | $second = (int) $time[2]; 547 | 548 | if ($day > 31 || $day < 1) { 549 | return false; 550 | } elseif ($hour > 24 || $hour < 0) { 551 | return false; 552 | } elseif ($minute > 60 || $minute < 0) { 553 | return false; 554 | } elseif ($second > 60 || $second < 0) { 555 | return false; 556 | } 557 | 558 | switch ($month) { 559 | case '01': 560 | $month = 0; 561 | break; 562 | case '02': 563 | $month = 1; 564 | break; 565 | case '03': 566 | $month = 2; 567 | break; 568 | case '04': 569 | $month = 3; 570 | break; 571 | case '05': 572 | $month = 4; 573 | break; 574 | case '06': 575 | $month = 5; 576 | break; 577 | case '07': 578 | $month = 6; 579 | break; 580 | case '08': 581 | $month = 7; 582 | break; 583 | case '09': 584 | $month = 8; 585 | break; 586 | case '10': 587 | $month = 9; 588 | break; 589 | case '11': 590 | $month = 10; 591 | break; 592 | case '12': 593 | $month = 11; 594 | break; 595 | default: 596 | return false; 597 | break; 598 | } 599 | 600 | return [$year, $month, $day, $hour, $minute, $second]; 601 | } 602 | 603 | /** 604 | * Parse DateTime information array to be in correct format. 605 | * 606 | * @param array $datetimeArray array contains information of DateTime in 607 | * `year, month, day, hour, minute, day` order. This parameter can be a 608 | * either associative or non-associative array. For the former, keys must 609 | * be compitiable with http://php.net/manual/en/function.getdate.php. For 610 | * missing pieces of information, a corresponded part from 1970/1/Jan., 00:00:00 611 | * will be replaced. 612 | * 613 | * @throws Exception 614 | * 615 | * @return array An `IntlDateFormatter` compatible array. 616 | */ 617 | private function parseDateTime($datetimeArray) 618 | { 619 | $finalDatetimeArray = []; 620 | 621 | if (!is_array($datetimeArray)) { 622 | throw new Exception('DateTime information must be an array in [year, month, day, hours, minutes, seconds] format.'); 623 | } 624 | 625 | $finalDatetimeArray[0] = isset($datetimeArray[0]) ? (int) $datetimeArray[0] : (isset($datetimeArray['year']) ? (int) $datetimeArray['year'] : 1970); 626 | $finalDatetimeArray[1] = isset($datetimeArray[1]) ? (int) $datetimeArray[1] - 1 : (isset($datetimeArray['mon']) ? (int) $datetimeArray['mon'] - 1 : 0); 627 | $finalDatetimeArray[2] = isset($datetimeArray[2]) ? (int) $datetimeArray[2] : (isset($datetimeArray['mday']) ? (int) $datetimeArray['mday'] : 1); 628 | $finalDatetimeArray[3] = isset($datetimeArray[3]) ? (int) $datetimeArray[3] : (isset($datetimeArray['hours']) ? (int) $datetimeArray['hours'] : 0); 629 | $finalDatetimeArray[4] = isset($datetimeArray[4]) ? (int) $datetimeArray[4] : (isset($datetimeArray['minutes']) ? (int) $datetimeArray['minutes'] : 0); 630 | $finalDatetimeArray[5] = isset($datetimeArray[5]) ? (int) $datetimeArray[5] : (isset($datetimeArray['seconds']) ? (int) $datetimeArray['seconds'] : 0); 631 | 632 | return $finalDatetimeArray; 633 | } 634 | 635 | public function setIntlDateFormatter( 636 | $locale = 'en_US', 637 | $datetype = IntlDateFormatter::FULL, 638 | $timetype = IntlDateFormatter::FULL, 639 | $timezone = 'UTC', 640 | $calendar = IntlDateFormatter::GREGORIAN, 641 | $pattern = 'yyyy/MM/dd HH:mm:ss' 642 | ) { 643 | $this->_intlDateFormatter = new IntlDateFormatter( 644 | $locale, // string $locale 645 | $datetype, // int $datetype 646 | $timetype, // int $timetype 647 | $timezone, // mixed $timezone 648 | $calendar, // mixed $calendar 649 | $pattern // string $pattern 650 | ); 651 | 652 | return $this; 653 | } 654 | 655 | public function getIntlDateFormatter() 656 | { 657 | return $this->_intlDateFormatter; 658 | } 659 | 660 | public function setIntlCalendar( 661 | $timezone = 'UTC', 662 | $locale = 'en_US@calendar=gregorian' 663 | ) { 664 | $this->_intlCalendar = IntlCalendar::createInstance( 665 | $timezone, 666 | $locale 667 | ); 668 | 669 | return $this; 670 | } 671 | 672 | public function getIntlCalendar() 673 | { 674 | return $this->_intlCalendar; 675 | } 676 | } 677 | --------------------------------------------------------------------------------