├── .coveralls.yml ├── .editorconfig ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml.dist ├── sami.php ├── src ├── Bridge │ ├── Symfony │ │ ├── CocurHumanDateBundle.php │ │ ├── CocurHumanDateExtension.php │ │ └── Translation │ │ │ └── SymfonyTranslation.php │ └── Twig │ │ └── HumanDateExtension.php ├── HumanDate.php └── Translation │ └── TranslationInterface.php └── tests ├── Bridge ├── Symfony │ ├── CocurHumanDateBundleTest.php │ ├── CocurHumanDateExtensionTest.php │ └── Translation │ │ └── SymfonyTranslationTest.php └── Twig │ └── HumanDateExtensionTest.php └── HumanDateTest.php /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci 2 | 3 | # for php-coveralls 4 | src_dir: src 5 | coverage_clover: build/logs/clover.xml 6 | json_path: build/logs/coveralls-upload.json 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | charset = utf-8 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.yml] 12 | indent_style = space 13 | indent_size = 2 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build/api 2 | /build/logs/ 3 | /cache/ 4 | /phpunit.xml 5 | /vendor/ 6 | /composer.lock 7 | /*.sublime-project 8 | /*.sublime-workspace 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.4 5 | - 5.5 6 | - 5.6 7 | - hhvm 8 | 9 | before_script: 10 | - wget http://getcomposer.org/composer.phar 11 | - php composer.phar --prefer-source --dev install 12 | - cp phpunit.xml.dist phpunit.xml 13 | 14 | script: 15 | - mkdir -p build/logs 16 | - ./vendor/bin/phpunit -c ./ 17 | 18 | after_script: 19 | - php vendor/bin/coveralls -v 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2012-2014 Florian Eckerstorfer 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | cocur/human-date 2 | ================ 3 | 4 | > Transforms dates into a human-readable format. 5 | 6 | [![Latest Stable Version](http://img.shields.io/packagist/v/cocur/human-date.svg)](https://packagist.org/packages/cocur/human-date) 7 | [![Build Status](http://img.shields.io/travis/cocur/human-date.svg)](https://travis-ci.org/cocur/human-date) 8 | [![Code Coverage](http://img.shields.io/coveralls/cocur/human-date.svg)](https://coveralls.io/r/cocur/human-date) 9 | 10 | 11 | Features 12 | -------- 13 | 14 | - Transforms dates into a human-readable format 15 | - Supports translatable strings 16 | - No external dependencies. 17 | - PSR-4 compatible. 18 | - Compatible with PHP >= 5.4 and [HHVM](http://hhvm.com). 19 | - Integrations for [Symfony2](http://symfony.com) and [Twig](http://twig.sensiolabs.org). 20 | 21 | 22 | Installation 23 | ------------ 24 | 25 | You can install `cocur/human-date` using [Composer](https://getcomposer.org): 26 | 27 | ```shell 28 | $ composer require cocur/human-date:@stable 29 | ``` 30 | 31 | *In a production environment you should replace `@stable` with the [version](https://github.com/cocur/human-date/releases) you want to use.* 32 | 33 | 34 | Usage 35 | ----- 36 | 37 | You can pass an instance of `DateTime` to the `HumanDate::transform()` method. For example, assuming that today is `2012-08-18`: 38 | 39 | ```php 40 | 41 | use Cocur\HumanDate\HumanDate; 42 | 43 | $humanDate = new HumanDate(); 44 | 45 | echo $humanDate->transform(new DateTime('now')); 46 | // 'Today' 47 | 48 | echo $humanDate->transform(new DateTime('+1 day')); 49 | // 'Tomorrow' 50 | 51 | echo $humanDate->transform(new DateTime('-1 day')); 52 | // 'Yesterday' 53 | 54 | echo $humanDate->transform(new DateTime('2012-08-21')); 55 | // 'Next Tuesday' 56 | 57 | echo $humanDate->transform(new DateTime('2012-09-30')); 58 | // 'September 30' 59 | 60 | echo $humanDate->transform(new DateTime('2013-03-30')); 61 | // 'March 30, 2013' 62 | ``` 63 | 64 | 65 | Translation 66 | ----------- 67 | 68 | HumanDate supports translation of strings. The `Cocur\HumanDate\HumanDate` constructor accepts an instance of `Cocur\HumanDate\Translation\TranslationInterface`. 69 | 70 | ```php 71 | $translation = MyTranslation(); // must implement `Cocur\HumanDate\Translation\TranslationInterface` 72 | $humanDate = new HumanDate($translation); 73 | 74 | echo $humanDate->transform(new DateTime('now')); 75 | // Calls MyTranslation::trans() 76 | ``` 77 | 78 | Additionally the library includes an adapter for the [Symfony Translation](http://symfony.com/doc/current/components/translation/index.html) component. 79 | 80 | 81 | Bridges 82 | ------- 83 | 84 | `cocur/human-date` contains bridges for Symfony and Twig. 85 | 86 | ### Symfony 87 | 88 | The Symfony bridge provides you with a bundle and an extension to use `HumanDate` as a service in your application. 89 | 90 | ```php 91 | # app/AppKernel.php 92 | 93 | class AppKernel extends Kernel 94 | { 95 | public function registerBundles() 96 | { 97 | $bundles = array( 98 | // ... 99 | new Cocur\HumanDate\Bridge\Symfony\CocurHumanDateBundle(), 100 | ); 101 | // ... 102 | } 103 | 104 | // ... 105 | } 106 | ``` 107 | 108 | You can now use the `cocur_human_date` service everywhere in your application, for example, in your controller: 109 | 110 | ```php 111 | $slug = $this->get('cocur_human_date')->slugify(new DateTime('2014-04-14')); 112 | ``` 113 | 114 | The bundle also provides an alias `human_date` for the `cocur_human_date` service: 115 | 116 | ```php 117 | $slug = $this->get('human_date')->slugify(new DateTime('2014-04-14')); 118 | ``` 119 | 120 | #### Translation 121 | 122 | HumanDate includes an adapter for the [Symfony Translation](http://symfony.com/doc/current/components/translation/index.html) component. The adapter requires an instance of `Symfony\Component\Translation\TranslatorInterface` and additionally accepts a translation domain and locale. The adapters `trans()` method passes theses values to every call of `Symfony\Component\Translation\TranslatorInterface::trans()`. 123 | 124 | ```php 125 | use Cocur\HumanDate\Bridge\Symfony\Translation\SymfonyTranslation; 126 | use Cocur\HumanDate\HumanDate; 127 | 128 | // Get or create an instance of Symfony\Component\Translation\TranslatorInterface 129 | // For example, inside a controller 130 | $sfTrans = $this->get('translation'); 131 | 132 | // Create an adapter with translation domain "human_date" and locale "en" 133 | // trans() passes domain and locale to every call of Symfony\Component\Translation\TranslatorInterface::trans() 134 | // If you omit the domain and locale it uses the defaults. 135 | $trans = new SymfonyTranslation($sfTrans, 'human_date', 'en'); 136 | 137 | $humanDate = new HumanDate($trans); 138 | ``` 139 | 140 | ### Twig 141 | 142 | If you use the Symfony2 framework with Twig you can use the Twig filter `humanDate` in your templates after you have setup Symfony2 integrations (see above). 143 | 144 | ```twig 145 | {{ post.createdAt|humanDate }} 146 | ``` 147 | 148 | If you use Twig outside of the Symfony2 framework you first need to add the extension to your environment: 149 | 150 | ```php 151 | use Cocur\HumanDate\Bridge\Twig\HumanDateExtension; 152 | use Cocur\HumanDate\HumanDate; 153 | 154 | $twig = new Twig_Environment($loader); 155 | $twig->addExtension(new HumanDateExtension(new HumanDate())); 156 | ``` 157 | 158 | You can find more information about registering extensions in the [Twig documentation](http://twig.sensiolabs.org/doc/advanced.html#creating-an-extension). 159 | 160 | 161 | Changelog 162 | --------- 163 | 164 | ### Version 0.1 (14 May 2014) 165 | 166 | - Initial version (ported from `BraincraftedHumanDateBundle`) 167 | 168 | 169 | Authors 170 | ------- 171 | 172 | - [Florian Eckerstorfer](http://florian.ec) ([Twitter](http://twitter.com/Florian_)) [![Support Florian](http://img.shields.io/gittip/florianeckerstorfer.svg)](https://www.gittip.com/FlorianEckerstorfer/) 173 | 174 | 175 | License 176 | ------- 177 | 178 | The MIT License (MIT) 179 | Copyright (c) 2012 Florian Eckerstorfer 180 | 181 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 182 | 183 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 184 | 185 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 186 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cocur/human-date", 3 | "description": "Transforms dates into a human-readable form", 4 | "keywords": ["date", "transformer", "human date"], 5 | "type": "library", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Florian Eckerstorfer", 10 | "email": "florian@eckerstorfer.co", 11 | "homepage": "https://florian.ec" 12 | } 13 | ], 14 | "require": { 15 | "php": ">=5.4" 16 | }, 17 | "require-dev": { 18 | "phpunit/phpunit": "~4.0", 19 | "mockery/mockery": "~0.9", 20 | "satooshi/php-coveralls": "dev-master", 21 | "symfony/http-kernel": "~2.4", 22 | "symfony/dependency-injection": "~2.4", 23 | "symfony/translation": "~2.4", 24 | "twig/twig": "~1", 25 | "sami/sami": "~1.3" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "Cocur\\HumanDate\\": "src" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | tests 7 | 8 | 9 | 10 | 11 | 12 | src 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /sami.php: -------------------------------------------------------------------------------- 1 | addFromTags('v0.*') 10 | ->add('master', 'master branch') 11 | ; 12 | 13 | return new Sami($dir, array( 14 | 'title' => 'HumanDate API', 15 | 'theme' => 'enhanced', 16 | 'versions' => $versions, 17 | 'build_dir' => __DIR__.'/build/api/%version%', 18 | 'cache_dir' => __DIR__.'/cache/api/%version%', 19 | 'default_opened_level' => 2, 20 | )); 21 | -------------------------------------------------------------------------------- /src/Bridge/Symfony/CocurHumanDateBundle.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cocur\HumanDate\Bridge\Symfony; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | use Symfony\Component\HttpKernel\Bundle\Bundle; 16 | 17 | /** 18 | * CocurHumanDateBundle 19 | * 20 | * @package cocur/human-date 21 | * @subpackage bridge 22 | * @author Florian Eckerstorfer 23 | * @copyright 2012-2014 Florian Eckerstorfer 24 | * @license http://opensource.org/licenses/MIT The MIT License 25 | */ 26 | class CocurHumanDateBundle extends Bundle 27 | { 28 | /** 29 | * {@inheritDoc} 30 | */ 31 | public function build(ContainerBuilder $container) 32 | { 33 | parent::build($container); 34 | 35 | $extension = new CocurHumanDateExtension(); 36 | $extension->load(array(), $container); 37 | 38 | $container->registerExtension($extension); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Bridge/Symfony/CocurHumanDateExtension.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cocur\HumanDate\Bridge\Symfony; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | use Symfony\Component\DependencyInjection\Definition; 16 | use Symfony\Component\DependencyInjection\Reference; 17 | use Symfony\Component\HttpKernel\DependencyInjection\Extension; 18 | 19 | /** 20 | * CocurHumanDateExtension 21 | * 22 | * @package cocur/human-date 23 | * @subpackage bridge 24 | * @author Florian Eckerstorfer 25 | * @copyright 2012-2014 Florian Eckerstorfer 26 | * @license http://opensource.org/licenses/MIT The MIT License 27 | */ 28 | class CocurHumanDateExtension extends Extension 29 | { 30 | /** 31 | * {@inheritDoc} 32 | */ 33 | public function load(array $configs, ContainerBuilder $container) 34 | { 35 | $container->setDefinition('cocur_human_date', new Definition('Cocur\HumanDate\HumanDate')); 36 | $container 37 | ->setDefinition( 38 | 'cocur_human_date.twig.human_date', 39 | new Definition( 40 | 'Cocur\HumanDate\Bridge\Twig\HumanDateExtension', 41 | array(new Reference('cocur_human_date')) 42 | ) 43 | ) 44 | ->addTag('twig.extension') 45 | ->setPublic(false); 46 | $container->setAlias('human_date', 'cocur_human_date'); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Bridge/Symfony/Translation/SymfonyTranslation.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cocur\HumanDate\Bridge\Symfony\Translation; 13 | 14 | use Cocur\HumanDate\Translation\TranslationInterface; 15 | use Symfony\Component\Translation\TranslatorInterface as SymfonyTranslationInterface; 16 | 17 | /** 18 | * SymfonyTranslation provides an adapter to translate strings using the Symfony Translation component. 19 | * 20 | * @package cocur/human-date 21 | * @subpackage bridge 22 | * @author Florian Eckerstorfer 23 | * @copyright 2012-2014 Florian Eckerstorfer 24 | * @license http://opensource.org/licenses/MIT The MIT License 25 | */ 26 | class SymfonyTranslation implements TranslationInterface 27 | { 28 | /** @var SymfonyTranslationInterface */ 29 | private $translation; 30 | 31 | /** @var string */ 32 | private $domain; 33 | 34 | /** @var string */ 35 | private $locale; 36 | 37 | /** 38 | * @param SymfonyTranslationInterface $translation Symfony translation 39 | * @param string $domain The domain for the message or null to use the default 40 | * @param string $locale The locale or null to use the default 41 | */ 42 | public function __construct(SymfonyTranslationInterface $translation, $domain = null, $locale = null) 43 | { 44 | $this->translation = $translation; 45 | $this->domain = $domain; 46 | $this->locale = $locale; 47 | } 48 | 49 | /** 50 | * @return SymfonyTranslationInterface 51 | */ 52 | public function getTranslation() 53 | { 54 | return $this->translation; 55 | } 56 | 57 | /** 58 | * @return string The domain for the message or null to use the default 59 | */ 60 | public function getDomain() 61 | { 62 | return $this->domain; 63 | } 64 | 65 | /** 66 | * @return string The locale or null to use the default 67 | */ 68 | public function getLocale() 69 | { 70 | return $this->locale; 71 | } 72 | 73 | /** 74 | * Translates the given message. 75 | * 76 | * @param string $message The message id (may also be an object that can be cast to string) 77 | * @param array $parameters An array of parameters for the message 78 | * 79 | * @return string The translated string 80 | */ 81 | public function trans($message, array $parameters = array()) 82 | { 83 | return $this->translation->trans($message, $parameters, $this->domain, $this->locale); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Bridge/Twig/HumanDateExtension.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cocur\HumanDate\Bridge\Twig; 13 | 14 | use \Twig_Extension; 15 | use \Twig_SimpleFilter; 16 | use \DateTimeInterface; 17 | 18 | use Cocur\HumanDate\HumanDate; 19 | 20 | /** 21 | * HumanDateExtension 22 | * 23 | * @package cocur/human-date 24 | * @subpackage bridge 25 | * @author Florian Eckerstorfer 26 | * @copyright 2012-2014 Florian Eckerstorfer 27 | * @license http://opensource.org/licenses/MIT The MIT License 28 | */ 29 | class HumanDateExtension extends Twig_Extension 30 | { 31 | /** @var HumanDate */ 32 | private $humanDate; 33 | 34 | /** 35 | * @param HumanDate $humanDate 36 | */ 37 | public function __construct(HumanDate $humanDate) 38 | { 39 | $this->humanDate = $humanDate; 40 | } 41 | 42 | /** 43 | * @return \Twig_SimpleFilter[] 44 | */ 45 | public function getFilters() 46 | { 47 | return array(new Twig_SimpleFilter('humanDate', array($this, 'humanDateFilter'))); 48 | } 49 | 50 | /** 51 | * @param DateTimeInterface $date 52 | * 53 | * @return string 54 | */ 55 | public function humanDateFilter($date) 56 | { 57 | return $this->humanDate->transform($date); 58 | } 59 | 60 | /** 61 | * {@inheritDoc} 62 | */ 63 | public function getName() 64 | { 65 | return 'human_date'; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/HumanDate.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cocur\HumanDate; 13 | 14 | use Cocur\HumanDate\Translation\TranslationInterface; 15 | use DateTime; 16 | use DateTimeInterface; 17 | use InvalidArgumentException; 18 | 19 | /** 20 | * HumanDate 21 | * 22 | * @package cocur/human-date 23 | * @author Florian Eckerstorfer 24 | * @copyright 2012-2014 Florian Eckerstorfer 25 | * @license http://opensource.org/licenses/MIT The MIT License 26 | */ 27 | class HumanDate 28 | { 29 | /** @var TranslationInterface */ 30 | private $translation; 31 | 32 | /** 33 | * @param TranslationInterface|null $translation Object to translate messages. 34 | */ 35 | public function __construct($translation = null) 36 | { 37 | if (null !== $translation && !$translation instanceof TranslationInterface) { 38 | throw new InvalidArgumentException('$translation must be null or an instance of TranslationInterface'); 39 | } 40 | 41 | $this->translation = $translation; 42 | } 43 | 44 | /** 45 | * @return TranslationInterface Object to translate messages. 46 | */ 47 | public function getTranslation() 48 | { 49 | return $this->translation; 50 | } 51 | 52 | /** 53 | * Transforms the given date into a human-readable date. 54 | * 55 | * @param DateTimeInterface|string $date Input date. 56 | * 57 | * @return string Human-readable date. 58 | */ 59 | public function transform($date) 60 | { 61 | if (!$date instanceof DateTimeInterface) { 62 | $date = new DateTime($date); 63 | } 64 | 65 | $current = new DateTime('now'); 66 | 67 | if ($this->isToday($date)) { 68 | return $this->trans('Today'); 69 | } 70 | 71 | if ($this->isYesterday($date)) { 72 | return $this->trans('Yesterday'); 73 | } 74 | 75 | if ($this->isTomorrow($date)) { 76 | return $this->trans('Tomorrow'); 77 | } 78 | 79 | if ($this->isNextWeek($date)) { 80 | return $this->trans('Next %weekday%', [ '%weekday%' => $date->format('l') ]); 81 | } 82 | 83 | if ($this->isLastWeek($date)) { 84 | return $this->trans('Last %weekday%', [ '%weekday%' => $date->format('l') ]); 85 | } 86 | 87 | if ($this->isThisYear($date)) { 88 | return $date->format('F j'); 89 | } 90 | 91 | return $date->format('F j, Y'); 92 | } 93 | 94 | /** 95 | * @param DateTimeInterface $date Date. 96 | * 97 | * @return boolean `true` if the given date is today, `false` otherwise. 98 | */ 99 | protected function isToday(DateTimeInterface $date) 100 | { 101 | $today = new DateTime('now'); 102 | $start = new DateTime($today->format('Y-m-d') . ' 00:00:00'); 103 | $end = new DateTime($today->format('Y-m-d') . ' 23:59:59'); 104 | 105 | if ($date->getTimestamp() >= $start->getTimestamp() && $date->getTimestamp() <= $end->getTimestamp()) { 106 | return true; 107 | } 108 | return false; 109 | } 110 | 111 | /** 112 | * @param DateTimeInterface $date Date. 113 | * 114 | * @return boolean `true` if the given date is tomorrow, `false` otherwise. 115 | */ 116 | protected function isTomorrow(DateTimeInterface $date) 117 | { 118 | $tomorrow = new DateTime('+1 day'); 119 | $start = new DateTime($tomorrow->format('Y-m-d') . ' 00:00:00'); 120 | $end = new DateTime($tomorrow->format('Y-m-d') . ' 23:59:59'); 121 | 122 | if ($date->getTimestamp() >= $start->getTimestamp() && $date->getTimestamp() <= $end->getTimestamp()) { 123 | return true; 124 | } 125 | return false; 126 | } 127 | 128 | /** 129 | * @param DateTimeInterface $date Date. 130 | * 131 | * @return boolean `true` if the given date is yesterday, `false` otherwise. 132 | */ 133 | protected function isYesterday(DateTimeInterface $date) 134 | { 135 | $yesterday = new DateTime('-1 day'); 136 | $start = new DateTime($yesterday->format('Y-m-d') . ' 00:00:00'); 137 | $end = new DateTime($yesterday->format('Y-m-d') . ' 23:59:59'); 138 | 139 | if ($date->getTimestamp() >= $start->getTimestamp() && $date->getTimestamp() <= $end->getTimestamp()) { 140 | return true; 141 | } 142 | return false; 143 | } 144 | 145 | /** 146 | * @param DateTimeInterface $date Date. 147 | * 148 | * @return boolean `true` if the given date is next week, `false` otherwise. 149 | */ 150 | protected function isNextWeek(DateTimeInterface $date) 151 | { 152 | $week = new DateTime('+7 days'); 153 | 154 | if ($date->getTimestamp() >= time() && $date->getTimestamp() <= $week->getTimestamp()) { 155 | return true; 156 | } 157 | return false; 158 | } 159 | 160 | /** 161 | * @param DateTimeInterface $date Date. 162 | * 163 | * @return boolean `true` if the given date is last week, `false` otherwise. 164 | */ 165 | protected function isLastWeek(DateTimeInterface $date) 166 | { 167 | $week = new DateTime('-7 days'); 168 | 169 | if ($date->getTimestamp() <= time() && $date->getTimestamp() >= $week->getTimestamp()) { 170 | return true; 171 | } 172 | return false; 173 | } 174 | 175 | /** 176 | * @param DateTimeInterface $date Date. 177 | * @return boolean `true` if the given date is this year, `false` otherwise. 178 | */ 179 | protected function isThisYear(DateTimeInterface $date) 180 | { 181 | if (date('Y') === $date->format('Y')) { 182 | return true; 183 | } 184 | return false; 185 | } 186 | 187 | /** 188 | * Translates the given message. 189 | * 190 | * @param string $id The message id (may also be an object that can be cast to string). 191 | * @param array $parameters An array of parameters for the message. 192 | * 193 | * @return string The translated message. 194 | */ 195 | protected function trans($id, array $parameters = array()) 196 | { 197 | if (null === $this->translation) { 198 | return str_replace(array_keys($parameters), array_values($parameters), $id); 199 | } 200 | 201 | return $this->translation->trans($id, $parameters); 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/Translation/TranslationInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cocur\HumanDate\Translation; 13 | 14 | /** 15 | * TranslationInterface 16 | * 17 | * @package cocur/human-date 18 | * @subpackage translation 19 | * @author Florian Eckerstorfer 20 | * @copyright 2012-2014 Florian Eckerstorfer 21 | * @license http://opensource.org/licenses/MIT The MIT License 22 | */ 23 | interface TranslationInterface 24 | { 25 | /** 26 | * Translates the given message. 27 | * 28 | * @param string $message The message id (may also be an object that can be cast to string) 29 | * @param array $parameters An array of parameters for the message 30 | * 31 | * @return string Translated message. 32 | */ 33 | public function trans($message, array $parameters = array()); 34 | } 35 | -------------------------------------------------------------------------------- /tests/Bridge/Symfony/CocurHumanDateBundleTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cocur\HumanDate\Bridge\Symfony; 13 | 14 | use Cocur\HumanDate\Bridge\Symfony\CocurHumanDateBundle; 15 | 16 | /** 17 | * CocurHumanDateBundleTest 18 | * 19 | * @category test 20 | * @package cocur/human-date 21 | * @subpackage bridge 22 | * @author Florian Eckerstorfer 23 | * @copyright 2012-2014 Florian Eckerstorfer 24 | * @license http://www.opensource.org/licenses/MIT The MIT License 25 | * @group unit 26 | */ 27 | class CocurHumanDateBundleTest extends \PHPUnit_Framework_TestCase 28 | { 29 | public function setUp() 30 | { 31 | $this->bundle = new CocurHumanDateBundle(); 32 | } 33 | 34 | /** 35 | * @test 36 | * @covers Cocur\HumanDate\Bridge\Symfony\CocurHumanDateBundle::build() 37 | */ 38 | public function build() 39 | { 40 | $container = $this->getMock( 41 | 'Symfony\Component\DependencyInjection\ContainerBuilder', 42 | array('registerExtension') 43 | ); 44 | $container->expects($this->once()) 45 | ->method('registerExtension') 46 | ->with($this->isInstanceOf('Cocur\HumanDate\Bridge\Symfony\CocurHumanDateExtension')); 47 | 48 | $this->bundle->build($container); 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /tests/Bridge/Symfony/CocurHumanDateExtensionTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cocur\HumanDate\Bridge\Bundle; 13 | 14 | use Cocur\HumanDate\Bridge\Symfony\CocurHumanDateExtension; 15 | use \Mockery as m; 16 | 17 | 18 | /** 19 | * CocurHumanDateExtensionTest 20 | * 21 | * @category test 22 | * @package cocur/human-date 23 | * @subpackage bridge 24 | * @author Florian Eckerstorfer 25 | * @copyright 2012-2014 Florian Eckerstorfer 26 | * @license http://www.opensource.org/licenses/MIT The MIT License 27 | * @group unit 28 | */ 29 | class CocurHumanDateExtensionTest extends \PHPUnit_Framework_TestCase 30 | { 31 | public function setUp() 32 | { 33 | $this->extension = new CocurHumanDateExtension(); 34 | } 35 | 36 | /** 37 | * @test 38 | * @covers Cocur\HumanDate\Bridge\Symfony\CocurHumanDateExtension::load() 39 | */ 40 | public function load() 41 | { 42 | $twigDefinition = m::mock('Symfony\Component\DependencyInjection\Definition'); 43 | $twigDefinition 44 | ->shouldReceive('addTag') 45 | ->with('twig.extension') 46 | ->once() 47 | ->andReturn($twigDefinition); 48 | $twigDefinition 49 | ->shouldReceive('setPublic') 50 | ->with(false) 51 | ->once(); 52 | 53 | $container = m::mock('Symfony\Component\DependencyInjection\ContainerBuilder'); 54 | $container 55 | ->shouldReceive('setDefinition') 56 | ->with('cocur_human_date', m::type('Symfony\Component\DependencyInjection\Definition')) 57 | ->once(); 58 | $container 59 | ->shouldReceive('setDefinition') 60 | ->with('cocur_human_date.twig.human_date', m::type('Symfony\Component\DependencyInjection\Definition')) 61 | ->once() 62 | ->andReturn($twigDefinition); 63 | $container 64 | ->shouldReceive('setAlias') 65 | ->with('human_date', 'cocur_human_date') 66 | ->once(); 67 | 68 | $this->extension->load(array(), $container); 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /tests/Bridge/Symfony/Translation/SymfonyTranslationTest.php: -------------------------------------------------------------------------------- 1 | symfonyTrans = m::mock('Symfony\Component\Translation\TranslatorInterface'); 24 | $this->trans = new SymfonyTranslation($this->symfonyTrans, 'foo', 'en'); 25 | } 26 | 27 | /** 28 | * @test 29 | * @covers Cocur\HumanDate\Bridge\Symfony\Translation\SymfonyTranslation::__construct() 30 | * @covers Cocur\HumanDate\Bridge\Symfony\Translation\SymfonyTranslation::getTranslation() 31 | */ 32 | public function getTranslation() 33 | { 34 | $this->assertEquals($this->symfonyTrans, $this->trans->getTranslation()); 35 | } 36 | 37 | /** 38 | * @test 39 | * @covers Cocur\HumanDate\Bridge\Symfony\Translation\SymfonyTranslation::__construct() 40 | * @covers Cocur\HumanDate\Bridge\Symfony\Translation\SymfonyTranslation::getDomain() 41 | */ 42 | public function getDomain() 43 | { 44 | $this->assertEquals('foo', $this->trans->getDomain()); 45 | } 46 | 47 | /** 48 | * @test 49 | * @covers Cocur\HumanDate\Bridge\Symfony\Translation\SymfonyTranslation::__construct() 50 | * @covers Cocur\HumanDate\Bridge\Symfony\Translation\SymfonyTranslation::getLocale() 51 | */ 52 | public function getLocale() 53 | { 54 | $this->assertEquals('en', $this->trans->getLocale()); 55 | } 56 | 57 | /** 58 | * @test 59 | * @covers Cocur\HumanDate\Bridge\Symfony\Translation\SymfonyTranslation::trans() 60 | */ 61 | public function trans() 62 | { 63 | $this->symfonyTrans 64 | ->shouldReceive('trans') 65 | ->with('string', [], 'foo', 'en') 66 | ->once() 67 | ->andReturn('translated string'); 68 | 69 | $this->assertEquals('translated string', $this->trans->trans('string')); 70 | } 71 | 72 | /** 73 | * @test 74 | * @covers Cocur\HumanDate\Bridge\Symfony\Translation\SymfonyTranslation::trans() 75 | */ 76 | public function transWithParameters() 77 | { 78 | $this->symfonyTrans 79 | ->shouldReceive('trans') 80 | ->with('string', [ 'key1' => 'val1' ], 'foo', 'en') 81 | ->once() 82 | ->andReturn('translated string'); 83 | 84 | $this->assertEquals('translated string', $this->trans->trans('string', [ 'key1' => 'val1' ])); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /tests/Bridge/Twig/HumanDateExtensionTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cocur\HumanDate\Bridge\Twig; 13 | 14 | use Cocur\HumanDate\Bridge\Twig\HumanDateExtension; 15 | use \Mockery as m; 16 | 17 | 18 | /** 19 | * HumanDateExtensionTest 20 | * 21 | * @category test 22 | * @package cocur/human-date 23 | * @subpackage bridge 24 | * @author Florian Eckerstorfer 25 | * @copyright 2012-2014 Florian Eckerstorfer 26 | * @license http://www.opensource.org/licenses/MIT The MIT License 27 | * @group unit 28 | */ 29 | class HumanDateExtensionTest extends \PHPUnit_Framework_TestCase 30 | { 31 | /** @var HumanDate */ 32 | private $humanDate; 33 | 34 | /** @var HumanDateExtension */ 35 | private $extension; 36 | 37 | public function setUp() 38 | { 39 | $this->humanDate = m::mock('Cocur\HumanDate\HumanDate'); 40 | $this->extension = new HumanDateExtension($this->humanDate); 41 | } 42 | 43 | /** 44 | * @test 45 | * @covers Cocur\HumanDate\Bridge\Twig\HumanDateExtension::getName() 46 | */ 47 | public function getName($withDataSet = true) 48 | { 49 | $this->assertEquals('human_date', $this->extension->getName()); 50 | } 51 | 52 | /** 53 | * @test 54 | * @covers Cocur\HumanDate\Bridge\Twig\HumanDateExtension::getFilters() 55 | */ 56 | public function getFilters() 57 | { 58 | $filters = $this->extension->getFilters(); 59 | 60 | $this->assertCount(1, $filters); 61 | $this->assertInstanceOf('\Twig_SimpleFilter', $filters[0]); 62 | } 63 | 64 | /** 65 | * @test 66 | * @covers Cocur\HumanDate\Bridge\Twig\HumanDateExtension::slugifyFilter() 67 | */ 68 | public function slugifyFilter() 69 | { 70 | $this->humanDate->shouldReceive('transform')->with('2014-05-14')->once()->andReturn('Today'); 71 | 72 | $this->assertEquals('Today', $this->extension->humanDateFilter('2014-05-14')); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/HumanDateTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cocur\HumanDate; 13 | 14 | use DateTime; 15 | use Cocur\HumanDate\HumanDate; 16 | use Mockery as m; 17 | 18 | /** 19 | * HumanDateTest 20 | * 21 | * @category test 22 | * @package cocur/human-date 23 | * @author Florian Eckerstorfer 24 | * @copyright 2012-2014 Florian Eckerstorfer 25 | * @license http://opensource.org/licenses/MIT The MIT License 26 | * @link https://github.com/braincrafted/human-date-bundle BraincraftedHumanDateBundle 27 | * @group unit 28 | */ 29 | class HumanDateTest extends \PHPUnit_Framework_TestCase 30 | { 31 | /** @var HumanDateTransformer */ 32 | protected $humanDate; 33 | 34 | public function setUp() 35 | { 36 | $this->humanDate = new HumanDate(); 37 | } 38 | 39 | /** 40 | * @test 41 | * @covers Cocur\HumanDate\HumanDate::__construct() 42 | * @expectedException \InvalidArgumentException 43 | */ 44 | public function constructorGetsInvalidTranslation() 45 | { 46 | new HumanDate('string'); 47 | } 48 | 49 | /** 50 | * @test 51 | * @covers Cocur\HumanDate\HumanDate::transform() 52 | * @covers Cocur\HumanDate\HumanDate::isToday() 53 | * @covers Cocur\HumanDate\HumanDate::isTomorrow() 54 | * @covers Cocur\HumanDate\HumanDate::isYesterday() 55 | * @covers Cocur\HumanDate\HumanDate::isNextWeek() 56 | * @covers Cocur\HumanDate\HumanDate::isLastWeek() 57 | * @covers Cocur\HumanDate\HumanDate::isThisYear() 58 | * @covers Cocur\HumanDate\HumanDate::trans() 59 | * @dataProvider provider 60 | */ 61 | public function transformDateTime($date, $expected) 62 | { 63 | $this->assertEquals($expected, $this->humanDate->transform(new DateTime($date))); 64 | } 65 | 66 | /** 67 | * @test 68 | * @covers Cocur\HumanDate\HumanDate::transform() 69 | * @covers Cocur\HumanDate\HumanDate::isToday() 70 | * @covers Cocur\HumanDate\HumanDate::isTomorrow() 71 | * @covers Cocur\HumanDate\HumanDate::isYesterday() 72 | * @covers Cocur\HumanDate\HumanDate::isNextWeek() 73 | * @covers Cocur\HumanDate\HumanDate::isLastWeek() 74 | * @covers Cocur\HumanDate\HumanDate::isThisYear() 75 | * @dataProvider provider 76 | */ 77 | public function transformString($date, $expected) 78 | { 79 | $this->assertEquals($expected, $this->humanDate->transform($date)); 80 | } 81 | 82 | /** 83 | * @return array[] 84 | */ 85 | public function provider() 86 | { 87 | return array( 88 | array('', 'Today'), 89 | array('-1 day', 'Yesterday'), 90 | array('+1 day', 'Tomorrow'), 91 | array('+3 days', 'Next '.date('l', strtotime('+3 days'))), 92 | array('-3 days', 'Last '.date('l', strtotime('-3 days'))), 93 | array('+30 days', date('F j', strtotime('+30 days'))), 94 | array('-30 days', date('F j', strtotime('-30 days'))), 95 | array((date('Y')+1).'-03-31', 'March 31, '.(date('Y')+1)), 96 | array((date('Y')-1).'-03-31', 'March 31, '.(date('Y')-1)) 97 | ); 98 | } 99 | 100 | /** 101 | * @test 102 | * @covers Cocur\HumanDate\HumanDate::transform() 103 | * @covers Cocur\HumanDate\HumanDate::isToday() 104 | * @covers Cocur\HumanDate\HumanDate::isTomorrow() 105 | * @covers Cocur\HumanDate\HumanDate::isYesterday() 106 | * @covers Cocur\HumanDate\HumanDate::isNextWeek() 107 | * @covers Cocur\HumanDate\HumanDate::isLastWeek() 108 | * @covers Cocur\HumanDate\HumanDate::isThisYear() 109 | * @covers Cocur\HumanDate\HumanDate::trans() 110 | * @dataProvider translatedProvider 111 | */ 112 | public function transformDateTimeWithTranslation($date, $expected) 113 | { 114 | $trans = m::mock('Cocur\HumanDate\Translation\TranslationInterface'); 115 | $trans->shouldReceive('trans')->with('Today', [])->andReturn('Heute'); 116 | $trans->shouldReceive('trans')->with('Yesterday', [])->andReturn('Gestern'); 117 | $trans->shouldReceive('trans')->with('Tomorrow', [])->andReturn('Morgen'); 118 | $trans 119 | ->shouldReceive('trans') 120 | ->with('Next %weekday%', [ '%weekday%' => date('l', strtotime('+3 days')) ]) 121 | ->andReturn('Nächsten '.date('l', strtotime('+3 days'))); 122 | $trans 123 | ->shouldReceive('trans') 124 | ->with('Last %weekday%', [ '%weekday%' => date('l', strtotime('-3 days')) ]) 125 | ->andReturn('Letzten '.date('l', strtotime('-3 days'))); 126 | 127 | $humanDate = new HumanDate($trans); 128 | $this->assertEquals($expected, $humanDate->transform(new DateTime($date))); 129 | } 130 | 131 | /** 132 | * @return array[] 133 | */ 134 | public function translatedProvider() 135 | { 136 | return array( 137 | array('', 'Heute'), 138 | array('-1 day', 'Gestern'), 139 | array('+1 day', 'Morgen'), 140 | array('+3 days', 'Nächsten '.date('l', strtotime('+3 days'))), 141 | array('-3 days', 'Letzten '.date('l', strtotime('-3 days'))), 142 | array('+30 days', date('F j', strtotime('+30 days'))), 143 | array('-30 days', date('F j', strtotime('-30 days'))), 144 | array((date('Y')+1).'-03-31', 'March 31, '.(date('Y')+1)), 145 | array((date('Y')-1).'-03-31', 'March 31, '.(date('Y')-1)) 146 | ); 147 | } 148 | } 149 | --------------------------------------------------------------------------------