diff --git a/README.md b/README.md index b781c79..43b7846 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,37 @@ use Coduo\PHPHumanizer\Number; echo Number::metricSuffix(1240000, 'pl'); // "1,24M" ``` +## Date time + +**Difference** + +```php +use Coduo\PHPHumanizer\DateTime; + +echo DateTime::difference(new \DateTime("2014-04-26 13:00:00"), new \DateTime("2014-04-26 13:00:00"); // just now +echo DateTime::difference(new \DateTime("2014-04-26 13:00:00"), new \DateTime("2014-04-26 13:00:05"); // 5 seconds from now +echo DateTime::difference(new \DateTime("2014-04-26 13:00:00"), new \DateTime("2014-04-26 12:59:00"); // 1 minute ago +echo DateTime::difference(new \DateTime("2014-04-26 13:00:00"), new \DateTime("2014-04-26 12:45:00"); // 15 minutes ago +echo DateTime::difference(new \DateTime("2014-04-26 13:00:00"), new \DateTime("2014-04-26 13:15:00"); // 15 minutes from now +echo DateTime::difference(new \DateTime("2014-04-26 13:00:00"), new \DateTime("2014-04-26 14:00:00"); // 1 hour from now +echo DateTime::difference(new \DateTime("2014-04-26 13:00:00"), new \DateTime("2014-04-26 15:00:00"); // 2 hours from now +echo DateTime::difference(new \DateTime("2014-04-26 13:00:00"), new \DateTime("2014-04-26 12:00:00"); // 1 hour ago +echo DateTime::difference(new \DateTime("2014-04-26"), new \DateTime("2014-04-25"); // 1 day ago +echo DateTime::difference(new \DateTime("2014-04-26"), new \DateTime("2014-04-24"); // 2 days ago +echo DateTime::difference(new \DateTime("2014-04-26"), new \DateTime("2014-04-28"); // 2 days from now +echo DateTime::difference(new \DateTime("2014-04-01"), new \DateTime("2014-04-15"); // 2 weeks from now +echo DateTime::difference(new \DateTime("2014-04-15"), new \DateTime("2014-04-07"); // 1 week ago +echo DateTime::difference(new \DateTime("2014-01-01"), new \DateTime("2014-04-01"); // 3 months from now +echo DateTime::difference(new \DateTime("2014-05-01"), new \DateTime("2014-04-01"); // 1 month ago +echo DateTime::difference(new \DateTime("2015-05-01"), new \DateTime("2014-04-01"); // 1 year ago +echo DateTime::difference(new \DateTime("2014-05-01"), new \DateTime("2016-04-01"); // 2 years from now + +``` + +Currently we support following languages: +* [English](src/Coduo/PHPHumanizer/Resources/translations/difference.en.yml) +* [Polish](src/Coduo/PHPHumanizer/Resources/translations/difference.pl.yml) + # Credits This lib was inspired by [Java Humanize Lib](https://github.com/mfornos/humanize) && [Rails Active Support](https://github.com/rails/rails/tree/master/activesupport/lib/active_support) diff --git a/composer.json b/composer.json index 172bcf6..807818f 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,9 @@ ], "require": { "php": ">=5.3.0", - "symfony/intl": "~2.3" + "symfony/intl": "~2.3", + "symfony/config": "~2.3", + "symfony/translation": "~2.3" }, "require-dev": { "phpspec/phpspec": "2.0.*" diff --git a/spec/Coduo/PHPHumanizer/DateTime/DifferenceSpec.php b/spec/Coduo/PHPHumanizer/DateTime/DifferenceSpec.php new file mode 100644 index 0000000..dc41b9e --- /dev/null +++ b/spec/Coduo/PHPHumanizer/DateTime/DifferenceSpec.php @@ -0,0 +1,106 @@ +beConstructedWith(new \DateTime("2014-04-26 13:00:00"), new \DateTime("2014-04-26 12:45:00")); + $this->getUnit()->shouldReturnAnInstanceOf('Coduo\PHPHumanizer\DateTime\Unit\Minute'); + $this->getQuantity()->shouldReturn(15); + $this->isPast()->shouldReturn(true); + } + + function it_calculate_diff_between_present_and_future_date_in_minutes() + { + $this->beConstructedWith(new \DateTime("2014-04-26 13:00:00"), new \DateTime("2014-04-26 13:15:00")); + $this->getUnit()->shouldReturnAnInstanceOf('Coduo\PHPHumanizer\DateTime\Unit\Minute'); + $this->getQuantity()->shouldReturn(15); + $this->isPast()->shouldReturn(false); + } + + function it_calculate_diff_between_present_and_past_date_in_hours() + { + $this->beConstructedWith(new \DateTime("2014-04-26 13:00:00"), new \DateTime("2014-04-26 11:00:00")); + $this->getUnit()->shouldReturnAnInstanceOf('Coduo\PHPHumanizer\DateTime\Unit\Hour'); + $this->getQuantity()->shouldReturn(2); + $this->isPast()->shouldReturn(true); + } + + function it_calculate_diff_between_present_and_future_date_in_hours() + { + $this->beConstructedWith(new \DateTime("2014-04-26 13:00:00"), new \DateTime("2014-04-26 16:00:00")); + $this->getUnit()->shouldReturnAnInstanceOf('Coduo\PHPHumanizer\DateTime\Unit\Hour'); + $this->getQuantity()->shouldReturn(3); + $this->isPast()->shouldReturn(false); + } + + function it_calculate_diff_between_present_and_past_date_in_days() + { + $this->beConstructedWith(new \DateTime("2014-04-10"), new \DateTime("2014-04-09")); + $this->getUnit()->shouldReturnAnInstanceOf('Coduo\PHPHumanizer\DateTime\Unit\Day'); + $this->getQuantity()->shouldReturn(1); + $this->isPast()->shouldReturn(true); + } + + function it_calculate_diff_between_present_and_future_date_in_days() + { + $this->beConstructedWith(new \DateTime("2014-04-10"), new \DateTime("2014-04-11")); + $this->getUnit()->shouldReturnAnInstanceOf('Coduo\PHPHumanizer\DateTime\Unit\Day'); + $this->getQuantity()->shouldReturn(1); + $this->isPast()->shouldReturn(false); + } + + function it_calculate_diff_between_present_and_past_date_in_weeks() + { + $this->beConstructedWith(new \DateTime("2014-04-15"), new \DateTime("2014-04-01")); + $this->getUnit()->shouldReturnAnInstanceOf('Coduo\PHPHumanizer\DateTime\Unit\Week'); + $this->getQuantity()->shouldReturn(2); + $this->isPast()->shouldReturn(true); + } + + function it_calculate_diff_between_present_and_future_date_in_weeks() + { + $this->beConstructedWith(new \DateTime("2014-04-01"), new \DateTime("2014-04-15")); + $this->getUnit()->shouldReturnAnInstanceOf('Coduo\PHPHumanizer\DateTime\Unit\Week'); + $this->getQuantity()->shouldReturn(2); + $this->isPast()->shouldReturn(false); + } + + function it_calculate_diff_between_present_and_past_date_in_months() + { + $this->beConstructedWith(new \DateTime("2014-04-01"), new \DateTime("2014-03-01")); + $this->getUnit()->shouldReturnAnInstanceOf('Coduo\PHPHumanizer\DateTime\Unit\Month'); + $this->getQuantity()->shouldReturn(1); + $this->isPast()->shouldReturn(true); + } + + function it_calculate_diff_between_present_and_future_date_in_months() + { + $this->beConstructedWith(new \DateTime("2014-04-01"), new \DateTime("2014-05-01")); + $this->getUnit()->shouldReturnAnInstanceOf('Coduo\PHPHumanizer\DateTime\Unit\Month'); + $this->getQuantity()->shouldReturn(1); + $this->isPast()->shouldReturn(false); + } + + function it_calculate_diff_between_present_and_past_date_in_years() + { + $this->beConstructedWith(new \DateTime("2014-01-01"), new \DateTime("2012-01-01")); + $this->getUnit()->shouldReturnAnInstanceOf('Coduo\PHPHumanizer\DateTime\Unit\Year'); + $this->getQuantity()->shouldReturn(2); + $this->isPast()->shouldReturn(true); + } + + function it_calculate_diff_between_present_and_future_date_in_years() + { + $this->beConstructedWith(new \DateTime("2014-01-01"), new \DateTime("2015-01-01")); + $this->getUnit()->shouldReturnAnInstanceOf('Coduo\PHPHumanizer\DateTime\Unit\Year'); + $this->getQuantity()->shouldReturn(1); + $this->isPast()->shouldReturn(false); + } +} diff --git a/spec/Coduo/PHPHumanizer/DateTime/FormatterSpec.php b/spec/Coduo/PHPHumanizer/DateTime/FormatterSpec.php new file mode 100644 index 0000000..97e08d8 --- /dev/null +++ b/spec/Coduo/PHPHumanizer/DateTime/FormatterSpec.php @@ -0,0 +1,48 @@ +beConstructedWith($translator); + $translator->transChoice( + 'minute.past', + 10, + array('%count%' => 10), + 'difference', + 'en' + )->willReturn('10 minutes ago'); + + $translator->transChoice( + 'minute.past', + 10, + array('%count%' => 10), + 'difference', + 'pl' + )->willReturn('10 minut temu'); + } + + function it_format_datetime_diff(Difference $diff) + { + $diff->getUnit()->willReturn(new Minute()); + $diff->getQuantity()->willReturn(10); + $diff->isPast()->willReturn(true); + $this->formatDifference($diff)->shouldReturn('10 minutes ago'); + } + + function it_format_datetime_diff_for_specific_locale(Difference $diff) + { + $diff->getUnit()->willReturn(new Minute()); + $diff->getQuantity()->willReturn(10); + $diff->isPast()->willReturn(true); + $this->formatDifference($diff, 'pl')->shouldReturn('10 minut temu'); + } +} diff --git a/spec/Coduo/PHPHumanizer/DateTimeSpec.php b/spec/Coduo/PHPHumanizer/DateTimeSpec.php new file mode 100644 index 0000000..8db4778 --- /dev/null +++ b/spec/Coduo/PHPHumanizer/DateTimeSpec.php @@ -0,0 +1,66 @@ +difference(new \DateTime($example[0]), new \DateTime($example[1]))->shouldReturn($example[2]); + } + } + + function it_humanize_difference_between_dates_for_pl_locale() + { + $examples = array( + array("2014-04-26 13:00:00", "2014-04-26 13:00:00", 'w tym momencie'), + array("2014-04-26 13:00:00", "2014-04-26 13:00:05", 'za 5 sekund'), + array("2014-04-26 13:00:00", "2014-04-26 12:59:00", 'minutę temu'), + array("2014-04-26 13:00:00", "2014-04-26 12:45:00", '15 minut temu'), + array("2014-04-26 13:00:00", "2014-04-26 13:15:00", 'za 15 minut'), + array("2014-04-26 13:00:00", "2014-04-26 14:00:00", 'za godzinę'), + array("2014-04-26 13:00:00", "2014-04-26 15:00:00", 'za 2 godziny'), + array("2014-04-26 13:00:00", "2014-04-26 12:00:00", 'godzinę temu'), + array("2014-04-26 13:00:00", "2014-04-26 15:00:00", 'za 2 godziny'), + array("2014-04-26 13:00:00", "2014-04-26 12:00:00", 'godzinę temu'), + array("2014-04-26", "2014-04-25", 'wczoraj'), + array("2014-04-26", "2014-04-24", '2 dni temu'), + array("2014-04-26", "2014-04-28", 'za 2 dni'), + array("2014-04-01", "2014-04-15", 'za 2 tygodnie'), + array("2014-04-15", "2014-04-07", 'tydzień temu'), + array("2014-01-01", "2014-04-01", 'za 3 miesiące'), + array("2014-05-01", "2014-04-01", 'miesiąc temu'), + array("2015-05-01", "2014-04-01", 'rok temu'), + array("2014-05-01", "2016-04-01", 'za 2 lata'), + array("2014-05-01", "2009-04-01", '5 lat temu'), + ); + + foreach ($examples as $example) { + $this->difference(new \DateTime($example[0]), new \DateTime($example[1]), 'pl')->shouldReturn($example[2]); + } + } +} diff --git a/src/Coduo/PHPHumanizer/DateTime.php b/src/Coduo/PHPHumanizer/DateTime.php new file mode 100644 index 0000000..c9f3e1c --- /dev/null +++ b/src/Coduo/PHPHumanizer/DateTime.php @@ -0,0 +1,16 @@ +formatDifference(new Difference($fromDate, $toDate), $locale); + } +} diff --git a/src/Coduo/PHPHumanizer/DateTime/Difference.php b/src/Coduo/PHPHumanizer/DateTime/Difference.php new file mode 100644 index 0000000..16cfe5a --- /dev/null +++ b/src/Coduo/PHPHumanizer/DateTime/Difference.php @@ -0,0 +1,92 @@ +fromDate = $fromDate; + $this->toDate = $toDate; + $this->calculate(); + } + + /** + * @return Unit + */ + public function getUnit() + { + return $this->unit; + } + + /** + * @return int + */ + public function getQuantity() + { + return $this->quantity; + } + + private function calculate() + { + /* @var $units \Coduo\PHPHumanizer\DateTime\Unit[] */ + $units = array( + new Year(), + new Month(), + new Week(), + new Day(), + new Hour(), + new Minute(), + new Second(), + new JustNow() + ); + + $absoluteMilliSecondsDiff = abs($this->toDate->getTimestamp() - $this->fromDate->getTimestamp()) * 1000; + foreach ($units as $unit) { + if ($absoluteMilliSecondsDiff >= $unit->getMilliseconds()) { + $this->unit = $unit; + break; + } + } + + + $this->quantity = ($absoluteMilliSecondsDiff == 0) + ? $absoluteMilliSecondsDiff + : (int) round($absoluteMilliSecondsDiff / $this->unit->getMilliseconds()); + } + + public function isPast() + { + $diff = $this->toDate->getTimestamp() - $this->fromDate->getTimestamp(); + return ($diff > 0) ? false : true; + } +} diff --git a/src/Coduo/PHPHumanizer/DateTime/Formatter.php b/src/Coduo/PHPHumanizer/DateTime/Formatter.php new file mode 100644 index 0000000..fc6b692 --- /dev/null +++ b/src/Coduo/PHPHumanizer/DateTime/Formatter.php @@ -0,0 +1,39 @@ +translator = $translator; + } + + /** + * @param Difference $difference + * @param string $locale + * @return string + */ + public function formatDifference(Difference $difference, $locale = 'en') + { + $translationKey = sprintf('%s.%s', $difference->getUnit()->getName(), $difference->isPast() ? 'past' : 'future'); + + return $this->translator->transChoice( + $translationKey, + $difference->getQuantity(), + array('%count%' => $difference->getQuantity()), + 'difference', + $locale + ); + } +} diff --git a/src/Coduo/PHPHumanizer/DateTime/Unit.php b/src/Coduo/PHPHumanizer/DateTime/Unit.php new file mode 100644 index 0000000..2957975 --- /dev/null +++ b/src/Coduo/PHPHumanizer/DateTime/Unit.php @@ -0,0 +1,18 @@ +getMilliseconds() * 24; + } +} diff --git a/src/Coduo/PHPHumanizer/DateTime/Unit/Hour.php b/src/Coduo/PHPHumanizer/DateTime/Unit/Hour.php new file mode 100644 index 0000000..c5134ed --- /dev/null +++ b/src/Coduo/PHPHumanizer/DateTime/Unit/Hour.php @@ -0,0 +1,22 @@ +getMilliseconds() * 60; + } +} diff --git a/src/Coduo/PHPHumanizer/DateTime/Unit/JustNow.php b/src/Coduo/PHPHumanizer/DateTime/Unit/JustNow.php new file mode 100644 index 0000000..3343d30 --- /dev/null +++ b/src/Coduo/PHPHumanizer/DateTime/Unit/JustNow.php @@ -0,0 +1,21 @@ +getMilliseconds() * 60; + } +} diff --git a/src/Coduo/PHPHumanizer/DateTime/Unit/Month.php b/src/Coduo/PHPHumanizer/DateTime/Unit/Month.php new file mode 100644 index 0000000..a4cd816 --- /dev/null +++ b/src/Coduo/PHPHumanizer/DateTime/Unit/Month.php @@ -0,0 +1,22 @@ +getMilliseconds() * 30; + } +} diff --git a/src/Coduo/PHPHumanizer/DateTime/Unit/Second.php b/src/Coduo/PHPHumanizer/DateTime/Unit/Second.php new file mode 100644 index 0000000..07ca8f8 --- /dev/null +++ b/src/Coduo/PHPHumanizer/DateTime/Unit/Second.php @@ -0,0 +1,21 @@ +getMilliseconds() * 7; + } +} diff --git a/src/Coduo/PHPHumanizer/DateTime/Unit/Year.php b/src/Coduo/PHPHumanizer/DateTime/Unit/Year.php new file mode 100644 index 0000000..f094402 --- /dev/null +++ b/src/Coduo/PHPHumanizer/DateTime/Unit/Year.php @@ -0,0 +1,22 @@ +getMilliseconds() * 356; + } +} diff --git a/src/Coduo/PHPHumanizer/Resources/translations/difference.en.yml b/src/Coduo/PHPHumanizer/Resources/translations/difference.en.yml new file mode 100644 index 0000000..ef82aa3 --- /dev/null +++ b/src/Coduo/PHPHumanizer/Resources/translations/difference.en.yml @@ -0,0 +1,24 @@ +just_now: + past: "just now" + future: "just now" +second: + past: "{1} %count% second ago|[2,Inf] %count% seconds ago" + future: "{1} %count% second from now|[2,Inf] %count% seconds from now" +minute: + past: "{1} %count% minute ago|[2,Inf] %count% minutes ago" + future: "{1} %count% minute from now|[2,Inf] %count% minutes from now" +hour: + past: "{1} %count% hour ago|[2,Inf] %count% hours ago" + future: "{1} %count% hour from now|[2,Inf] %count% hours from now" +day: + past: "{1} %count% day ago|[2,Inf] %count% days ago" + future: "{1} %count% day from now|[2,Inf] %count% days from now" +week: + past: "{1} %count% week ago|[2,Inf] %count% weeks ago" + future: "{1} %count% week from now|[2,Inf] %count% weeks from now" +month: + past: "{1} %count% month ago|[2,Inf] %count% months ago" + future: "{1} %count% month from now|[2,Inf] %count% months from now" +year: + past: "{1} %count% year ago|[2,Inf] %count% years ago" + future: "{1} %count% year from now|[2,Inf] %count% years from now" diff --git a/src/Coduo/PHPHumanizer/Resources/translations/difference.pl.yml b/src/Coduo/PHPHumanizer/Resources/translations/difference.pl.yml new file mode 100644 index 0000000..da237d8 --- /dev/null +++ b/src/Coduo/PHPHumanizer/Resources/translations/difference.pl.yml @@ -0,0 +1,24 @@ +just_now: + past: "w tym momencie" + future: "w tym momencie" +second: + past: "{1} sekundę temu|[2, 4] %count% sekundy temu|[5,Inf] %count% sekund temu" + future: "{1} za sekundę|[2, 4] za %count% sekund|[5,Inf] za %count% sekund" +minute: + past: "{1} minutę temu|[2, 4] %count% minuty temu|[5,Inf] %count% minut temu" + future: "{1} za minutę|[2, 4] za %count% minuty|[5,Inf] za %count% minut" +hour: + past: "{1} godzinę temu|[2, 4] %count% godziny temu|[5,Inf] %count% godzin temu" + future: "{1} za godzinę|[2, 4] za %count% godziny|[5,Inf] za %count% godzin" +day: + past: "{1} wczoraj|[2, Inf] %count% dni temu" + future: "{1} jutro|[2, Inf] za %count% dni" +week: + past: "{1} tydzień temu|[2, 4] %count% tygodnie temu|[5,Inf] %count% tygodni temu" + future: "{1} za tydzień|[2, 4] za %count% tygodnie|[5,Inf] za %count% tygodni" +month: + past: "{1} miesiąc temu|[2, 4] %count% miesiące temu|[5,Inf] %count% miesięcy temu" + future: "{1} za miesiąc|[2, 4] za %count% miesiące|[5,Inf] za %count% miesięcy" +year: + past: "{1} rok temu|[2, 4] %count% lata temu|[5,Inf] %count% lat temu" + future: "{1} za rok|[2, 4] za %count% lata|[5,Inf] za %count% lat" diff --git a/src/Coduo/PHPHumanizer/Translator/Builder.php b/src/Coduo/PHPHumanizer/Translator/Builder.php new file mode 100644 index 0000000..da44e79 --- /dev/null +++ b/src/Coduo/PHPHumanizer/Translator/Builder.php @@ -0,0 +1,27 @@ +addLoader('yml', new YamlFileLoader()); + + $iterator = new \FilesystemIterator(__DIR__ . "/../Resources/translations"); + $filter = new \RegexIterator($iterator, '/[aA-zZ]+\.[a-z]{2}\.yml$/'); + + foreach($filter as $file) { + /* @var $file \SplFileInfo */ + $resourceName = $file->getBasename('.yml'); + list($fileDomain, $fileLocale) = explode('.', $resourceName); + $translator->addResource('yml', $file->getPathname(), $fileLocale, $fileDomain); + } + + return $translator; + } +}