Suggesting Carbon with Composer – Date and Time the Right Way
Carbon is a small library for date and time manipulation in PHP. It relies on and extends the core DateTime class, adding helpful methods for a significantly saner experience.
In this article, we’ll take a look at some basic usage examples, and then use it in a real project.
Key Takeaways
- Carbon is a PHP library designed for date and time manipulation, extending the core DateTime class and adding user-friendly methods for a more intuitive experience.
- The library can be installed with Composer and can be instantiated from strings, timestamps, or other instances of DateTime or Carbon. It provides helper checkers and getters for various date and time related operations.
- Carbon supports localization, allowing output to be given in any desired language installed on the machine powering the PHP app. It also provides a CarbonInterval class for holding interval values and additional helper methods.
- An example of implementing Carbon in a project is shown through upgrading the Diffbot PHP Client to support Carbon. If the user has the library installed, then the Article entity and Post entity return Carbon instances instead of date strings from their getDate and getEstimatedDate methods.
Introduction
Carbon is just a class which is designed to be used instead of DateTime. Due to extending DateTime, all DateTime methods are available to users of Carbon. Additionally, it implements a __toString
method, allowing users to put it in place of string representations of date and time as well.
It can easily be installed with Composer:
composer require nesbot/carbon
Let’s see some example uses, as presented in their excellent documentation.
Example Uses
The easiest way to get started with Carbon is to just pass a human readable date string into its constructor, along with an optional timezone – if the timezone is omitted, the one set by the current PHP installation will be used.
$carbon = new Carbon('first day of next week');
It can also be instantiated from strings, timestamps, even other instances of DateTime or even Carbon. The instance can be copied with the copy()
method, for efficient cloning.
From there, we have access to a smorgasbord of helper checkers and getters:
$carbon->isWeekend();
$carbon->isFuture();
$carbon->isLeapYear();
$carbon->year;
$carbon->month;
$carbon->daysInMonth;
$carbon->weekOfYear;
The package also exposes static methods for creating new instances quickly:
echo Carbon::now()->addYear()->diffForHumans(); // in 1 year
Even birthdays can be checked, as we can see by this example from the docs:
$born = Carbon::createFromDate(1987, 4, 23);
$noCake = Carbon::createFromDate(2014, 9, 26);
$yesCake = Carbon::createFromDate(2014, 4, 23);
$overTheHill = Carbon::now()->subYears(50);
var_dump($born->isBirthday($noCake)); // bool(false)
var_dump($born->isBirthday($yesCake)); // bool(true)
var_dump($overTheHill->isBirthday()); // bool(true) -> default compare it to today!
Localization
Localization is also supported, so that output can be given in any desired language installed on the machine powering the PHP app. Note that you do need to install the necessary locales for this to work – refer to your operating system’s documentation for details on how to do that.
To localize date and time strings, the standard PHP function setlocale
can be used:
setlocale(LC_TIME, 'German');
echo $dt->formatLocalized('%A %d %B %Y'); // Mittwoch 21 Mai 1975
To localize the diffForHumans
method which outputs a human-readable difference in time, the class offers its own setLocale
method:
Carbon::setLocale('de');
echo Carbon::now()->addYear()->diffForHumans(); // in 1 Jahr
Interval
A CarbonInterval class is also provided, which is an extension of DateInterval. Self-descriptively, it holds interval values, just like the base class, but adds helper methods on top. As per examples:
echo CarbonInterval::year(); // 1 year
echo CarbonInterval::months(3); // 3 months
echo CarbonInterval::days(3)->seconds(32); // 3 days 32 seconds
echo CarbonInterval::weeks(3); // 3 weeks
echo CarbonInterval::days(23); // 3 weeks 2 days
echo CarbonInterval::create(2, 0, 5, 1, 1, 2, 7); // 2 years 5 weeks 1 day 1 hour 2 minutes 7 seconds
Note that Carbon as a whole is exceptionally well documented – for a full reference of methods and usage examples, please see their docs.
Implementation
In this section, we’ll upgrade the Diffbot PHP Client to optionally support Carbon. The plan is as follows: if the user has the library installed, then the Article entity and Post entity will return Carbon instances instead of date strings from their getDate
and getEstimatedDate
methods. Otherwise, they’ll return strings as usual.
If you’d like to follow along, clone the client at this version.
Composer Suggests
The first step is to add the library to the suggests
list in composer.json
. The suggests
list takes the same format as the require
blocks, but instead of version constraints, we put full string messages on why that package is suggested.
"suggest": {
"nesbot/carbon": "Turns the date and estimatedDate return values of Article and Post entity into Carbon entities."
},
We can make sure we got the syntax right by running composer validate
:
vagrant@homestead:~/Code/diffbot-php-client$ composer validate
./composer.json is valid
When a user installs the Diffbot PHP Client, they’ll see a recommendation to install Carbon.
Tests
Next, it’s time to update the tests to accommodate for this.
In tests/Entities/ArticleTest.php
, we alter the dateProvider
and testDate
functions like so:
public function dateProvider()
{
return [
[
'Articles/diffbot-sitepoint-basic.json',
"Sun, 27 Jul 2014 00:00:00 GMT",
2014
],
[
'Articles/diffbot-sitepoint-extended.json',
"Sun, 27 Jul 2014 00:00:00 GMT",
2014
],
[
'Articles/apple-watch-verge-basic.json',
"Wed, 08 Apr 2015 00:00:00 GMT",
2015
],
[
'Articles/apple-watch-verge-extended.json',
"Wed, 08 Apr 2015 00:00:00 GMT",
2015
]
];
}
/**
* @param $file
* @param $articles
* @dataProvider dateProvider
*/
public function testDate($file, $articles, $year)
{
$articles = (is_array($articles)) ? $articles : [$articles];
/** @var Article $entity */
foreach ($this->ei($file) as $i => $entity) {
$this->assertEquals($articles[$i], $entity->getDate());
if (class_exists('\Carbon\Carbon')) {
$this->assertEquals($year, $entity->getDate()->year);
}
}
}
What happened here?
First, we added year values into the provider as the third argument to be passed into testDate
. Then, during iteration and assertion, we first check if the class is loaded / exists, and if so, we test for one of its getters (->year
).
We have to check if the class exists before testing, because Carbon is optional in the Diffbot SDK – it’s just a suggestion, so we mustn’t fail if it isn’t there.
We repeat the process for estimatedDateProvider
and estimatedDate
at the bottom of the ArticleTest
class:
public function estimatedDateProvider()
{
return [
['Articles/15-11-07/diffbot-sitepoint-basic.json', 'Sun, 27 Jul 2014 00:00:00 GMT', 2014],
];
}
/**
* @dataProvider estimatedDateProvider
* @param $file
* @param $value1
*/
public function testEstimatedDate($file, $value1, $value2)
{
$value1 = (is_array($value1)) ? $value1 : [$value1];
/** @var Article $entity */
foreach ($this->ei($file) as $i => $entity) {
$this->assertEquals($value1[$i], $entity->getEstimatedDate());
if (class_exists('\Carbon\Carbon')) {
$this->assertEquals($value2, $entity->getDate()->year);
}
}
}
Next, let’s update the PostTest
class. That one only has the getDate
method, but involves a bit more typing because a Discussion almost always returns multiple posts.
{
return [
[
'Discussions/15-05-01/sp_discourse_php7_recap.json',
[
"Wed, 29 Apr 2015 16:00:00 GMT",
"Thu, 30 Apr 2015 01:13:00 GMT",
"Thu, 30 Apr 2015 05:55:00 GMT",
"Thu, 30 Apr 2015 06:57:00 GMT",
"Thu, 30 Apr 2015 07:51:00 GMT",
"Thu, 30 Apr 2015 09:29:00 GMT",
"Thu, 30 Apr 2015 10:26:00 GMT",
"Thu, 30 Apr 2015 10:40:00 GMT",
"Thu, 30 Apr 2015 11:06:00 GMT",
"Thu, 30 Apr 2015 11:29:00 GMT",
"Thu, 30 Apr 2015 14:33:00 GMT",
"Thu, 30 Apr 2015 15:48:00 GMT",
"Thu, 30 Apr 2015 16:17:00 GMT",
"Thu, 30 Apr 2015 16:51:00 GMT",
"Thu, 30 Apr 2015 17:02:00 GMT",
"Fri, 01 May 2015 08:00:00 GMT",
],
[
2015,
2015,
2015,
2015,
2015,
2015,
2015,
2015,
2015,
2015,
2015,
2015,
2015,
2015,
2015,
2015,
]
]
];
}
/**
* @param $file
* @param $posts
* @dataProvider dateProvider
*/
public function testDate($file, $posts, $years)
{
/** @var Discussion $entity */
foreach ($this->ei($file) as $entity) {
/** @var Post $post */
foreach ($entity->getPosts() as $i => $post) {
$this->assertEquals($posts[$i], $post->getDate());
if (class_exists('\Carbon\Carbon')) {
$this->assertEquals($years[$i], $post->getDate()->year);
}
}
}
}
If we now attempt to run these tests, they will succeed. If we install Carbon into the project with:
composer require nesbot/carbon --dev
… the tests will fail.
Implementation
It’s time to change the actual entities now.
Diffbot returns dates in the following format: Sun, 27 Jul 2014 00:00:00 GMT
.
In order to maintain backwards compatibility, we need to set Carbon to produce the same output when used as a string (via __toString
), so that everyone who used the date values as output directly can still do so. This is done with the static Carbon::setToStringFormat($format);
method.
Adding the following to the constructor in src/Entity/Article.php
will accomplish this:
if (class_exists('\Carbon\Carbon')) {
$format = 'D, d M o H:i:s e';
\Carbon\Carbon::setToStringFormat($format);
}
The same must be added to the src/Entity/Post.php
file, though that one still doesn’t override the base class’ constructor and needs to do that first. The final version of Post
‘s construct method is:
public function __construct(array $data)
{
if (class_exists('\Carbon\Carbon')) {
$format = 'D, d M o H:i:s e';
\Carbon\Carbon::setToStringFormat($format);
}
parent::__construct($data);
}
Now that we’ve got Carbon activated and defaulting to a format we want, it’s time to upgrade our getters.
In both Article
and Post
, the getDate
method should now look like this:
public function getDate()
{
return (class_exists('\Carbon\Carbon')) ?
new \Carbon\Carbon($this->data['date'], 'GMT') :
$this->data['date'];
}
If Carbon exists, make a new instance from the post’s date in the GMT timezone (the timezone Diffbot always returns), otherwise, return the date string as before.
Finally, we need to change getEstimatedDate
in Article
:
public function getEstimatedDate()
{
$date = $this->getOrDefault('estimatedDate', $this->getDate());
return (class_exists('\Carbon\Carbon')) ?
new \Carbon\Carbon($date, 'GMT') :
$date;
}
Same thing, only this one first defaults to getDate
if the estimatedDate
could not be determined.
Running the tests should now show everything passing:
vagrant@homestead:~/Code/diffbot-php-client$ phpunit
PHPUnit 5.0.8 by Sebastian Bergmann and contributors.
Runtime: PHP 5.6.10-1+deb.sury.org~trusty+1 with Xdebug 2.3.2
Configuration: /home/vagrant/Code/diffbot-php-client/phpunit.xml.dist
............................................................... 63 / 352 ( 17%)
............................................................... 126 / 352 ( 35%)
............S.................................................. 189 / 352 ( 53%)
............................................................... 252 / 352 ( 71%)
............................................................... 315 / 352 ( 89%)
..................................... 352 / 352 (100%)
Time: 49.39 seconds, Memory: 21.00Mb
Success! We can now commit, push, and publish a new release!
Conclusion
We looked at Carbon, an extension of DateTime which adds helpful methods to the core class and make it much more pleasant to use. We saw how easy it is to implement in a project, and how it can replace pure string outputs and timestamps by means of different internal string formats.
Are you using Carbon in your projects? What do you like or dislike about it? Leave your thoughts and comments below, and if you liked this post, don’t forget to hit that thumbs up button!
Frequently Asked Questions about Carbon with Composer, Date and Time
Why should I use Carbon with Composer for date and time management in PHP?
Carbon is a simple PHP API extension for DateTime. It provides a more user-friendly and intuitive interface for handling date and time in PHP. It includes several helpful methods and constants to make working with dates and times easier. Using Carbon with Composer allows you to manage dependencies and ensure that your project has the correct versions of necessary packages, including Carbon.
How do I install Carbon with Composer?
To install Carbon with Composer, you need to run the command composer require nesbot/carbon
. This command tells Composer to download the Carbon package and add it as a dependency in your project. Once the installation is complete, you can use Carbon in your PHP scripts by including the autoloader with require 'vendor/autoload.php';
.
What are the benefits of using Carbon over native PHP DateTime functions?
Carbon provides several advantages over native PHP DateTime functions. It offers a more intuitive and fluent interface, making it easier to work with dates and times. It also includes several additional methods for common tasks, such as formatting dates, calculating differences between dates, and manipulating dates.
How do I format dates using Carbon?
Carbon provides several methods for formatting dates. For example, you can use the format
method to format a date according to a specified format. You can also use methods like toDateString
, toDateTimeString
, and toDayDateTimeString
to format dates in common formats.
How do I calculate the difference between two dates using Carbon?
Carbon provides several methods for calculating the difference between two dates. The diff
method returns a DateInterval object representing the difference between two dates. You can also use methods like diffInDays
, diffInHours
, and diffInMinutes
to calculate the difference in specific units.
How do I manipulate dates using Carbon?
Carbon provides several methods for manipulating dates. For example, you can use the addDays
, subDays
, addHours
, and subHours
methods to add or subtract days or hours from a date. You can also use the startOfDay
, endOfDay
, startOfMonth
, and endOfMonth
methods to set a date to the start or end of a day or month.
How do I compare dates using Carbon?
Carbon provides several methods for comparing dates. The equalTo
, notEqualTo
, greaterThan
, greaterThanOrEqualTo
, lessThan
, and lessThanOrEqualTo
methods allow you to compare two dates and determine their relative order.
How do I convert a Carbon instance to a DateTime instance?
You can convert a Carbon instance to a DateTime instance using the toDateTime
method. This method returns a DateTime instance representing the same point in time as the Carbon instance.
How do I handle timezones with Carbon?
Carbon provides several methods for handling timezones. The timezone
method allows you to set the timezone for a Carbon instance. You can also use the tz
method as a shorthand for this. The shiftTimezone
method allows you to shift a date to a different timezone, adjusting the time accordingly.
How do I handle localization with Carbon?
Carbon provides several methods for handling localization. The locale
method allows you to set the locale for a Carbon instance, which affects the output of methods like formatLocalized
. You can also use the setLocale
method to set the locale globally for all Carbon instances.
Bruno is a blockchain developer and technical educator at the Web3 Foundation, the foundation that's building the next generation of the free people's internet. He runs two newsletters you should subscribe to if you're interested in Web3.0: Dot Leap covers ecosystem and tech development of Web3, and NFT Review covers the evolution of the non-fungible token (digital collectibles) ecosystem inside this emerging new web. His current passion project is RMRK.app, the most advanced NFT system in the world, which allows NFTs to own other NFTs, NFTs to react to emotion, NFTs to be governed democratically, and NFTs to be multiple things at once.

Published in
·APIs·Authentication·CMS & Frameworks·Database·Frameworks·PHP·Web Services·August 26, 2016
Published in
·APIs·Cloud·CMS & Frameworks·Google·Miscellaneous·PHP·Programming·Statistics and Analysis·Web·November 7, 2014
Published in
·Accessibility·Community·Patterns & Practices·Statistics and Analysis·UX·Web·March 31, 2014