Skip to content

Instantly share code, notes, and snippets.

@kylekatarnls
Last active March 8, 2019 13:13
Show Gist options
  • Save kylekatarnls/ecfa3267a02165e758894d324cce8344 to your computer and use it in GitHub Desktop.
Save kylekatarnls/ecfa3267a02165e758894d324cce8344 to your computer and use it in GitHub Desktop.
Carbon 2 proposal

Carbon 2 (Draft)

Complete set of PHP Date classes extensions:

class extends comment
Carbon DateTime
CarbonImmutable DateTimeImmutable new
CarbonInterface DateTimeInterface new
CarbonTimeZone DateTimeZone new
CarbonInterval DateInterval Read-only days property
CarbonPeriod DatePeriod Blocked until php/php-src#3121 get merged

Setter methods of Carbon become cloners in CarbonImmutable:

$m = new Carbon;
$c1 = $m->setDay(1);
// $m->day === $c1->day as $c1 === $m
$i = new CarbonImmutable;
$c2 = $i->setDay(1);
// $m->day !== $c2->day as $c2 is a new object
$c1->day = 9; // $m->day === 9
$c2->day = 9; // error, immutable

Generic methods

To reduce code amount, we could rather have a magic __call method parsing methods matching actionUnit with action in a given list (isSame, isCurrent, add, sub, get, set, floor, ceil, round, etc.) and unit as valid unit (second, minute, hour, day, etc.) to route to generic method (action) with a unit argument.

This will enforce some methods consistency (easy way to handle singular/plural, same arguments for a given action). And a easier way to add actions. This would encourage to drop boolean arguments (which give multiple responsability to a single method) in favor of adding methods.

A automated script could update the PHPDoc comment to add @method annotations so even if the methods does not really exist, IDE autocompletion will propose magic methods and we would not have to add them all manually.

Having a methods set compatible with https://momentjs.com could help to create a full-stack standard.

Stricter extends

Critical methods should be final (macro methods, magic methods) so it would help us to prevent breaking changes in sub-classes.

All methods in traits

Methods should be grouped in traits and each trait should remain stand-alone (could be taken alone).

Instead of extends the Carbon classes, users would be able to compose their own date classes picking traits.

Documentation

Documentation could be interactive (see https://pug-demo.herokuapp.com and https://phug-lang.com/, it provides code examples the user can edit in live to see the PHP result).

Carbon become big, the single-page and one-level links menu will become a bit too limited, some search/expand/collapse tools would help to browse it.

Each method must be documented with minimal informations:

  • history, example: added in 2.1.0, argument $foo added in 2.2.0, $foo can be an array since 2.2.1
  • trait, example: set() belongs to Setter trait
  • arguments, return and exceptions thrown
  • code examples

Requirement

To provide reliable solid library, Carbon should rely on a full microseconds support, that means at least PHP 7.1.8.

About version 1.x

Carbon is widely used. We should not abandon v1 users.

  • V1 documentation must remain available
  • An issue templating and 1.x/2.x tagging will help to handle issues
  • A migration guide could help user to upgrade
  • Dropped methods could remain in the documentation (tagged as obsolete with some gray-styling and collapsed description)
@kylekatarnls
Copy link
Author

Translator seems always simple at first sight, sounds like just a big mapping. But check the size of https://github.com/symfony/translation, it's not filled with air, it's really how tricky is the translation rules. Just have a look at pluralization rules to start: https://github.com/symfony/translation/blob/master/PluralizationRules.php

Nearly all the languages are already configured and ready to translate, ready to be customized by end-users and already documented. And Symfony is very well maintained so if a language is missing (it happened only once until now) they are very reactive, last time, they merged in less than 24 hours: symfony/symfony#27286

The symfony/translation dependency also means consistency between the app and Carbon for each one using Symfony/Laravel.

I prefer to focus on date features and rely on a dedicated package for translation.

About mutable/immutable, there are common ways. modify() exists on both for example but returns new object with Immutable. So we can create common interfaces like Modifyable and trait with common methods using modify() no matter it's mutable or not, then on unit tests, we can have a standard way to check it:

protected function assertCarbonModification($expected, $source, $modification)
{
    $actual = $modification($source);
    self::assertEquals($expected, $actual);
    $method = 'assert'.($source instanceof DateTimeImmutable ? 'Not' : '').'Same';
    self::$method($expected, $actual);
}

@kylekatarnls
Copy link
Author

kylekatarnls commented Jun 17, 2018

floor/ceil/round is nearly finished in my local env.

Quick overview about momentjs compatibility (including briannesbitt/Carbon#1360):

Method exists is compatible
add x x
calendar x x
clone x x
creationData
date (4) (4)
dates (3) (3)
day x
dayOfYear x x
days x
daysInMonth (4) (4)
diff x
endOf x x
format x x(2)
from x x
fromNow x x
get x x
hasAlignedHourOffset
hour x x
hours x x
inspect
invalidAt
isAfter x x
isBefore x x
isBetween x x
isDST x x
isDSTShifted (3) (3)
isLeapYear x x
isLocal x x
isSame
isSameOrAfter
isSameOrBefore
isUTC x x
isUtc x x
isUtcOffset
isValid x x
isoWeek x x
isoWeekYear x x
isoWeekday x x
isoWeeks x x
isoWeeksInYear x x
lang (3) (3)
local
locale x x
localeData
max x (1)
millisecond x x
milliseconds x x
min x (1)
minute x x
minutes x x
month x x
months x x
parseZone
parsingFlags
quarter x x
quarters x x
second x x
seconds x x
set x x
startOf x x
subtract x x
to x x
toArray x
toDate x x
toISOString x x
toJSON x x
toNow x x
toObject x x
toString x x
tz x
unix x x
utc x x
utcOffset x x
valueOf x x
week x x
weekYear x x
weekday x x
weeks x x
weeksInYear x x
year x x
years x x
zone (3) (3)
zoneAbbr (3) (3)
zoneName (3) (3)

(1) min and max are deprecated because of an inverted behavior, our behavior match the non-inverted behavior. Moment also have a static method which could be nice to have for min/max.
(2) format in momentjs is isoFormat in Carbon to keep original format method from DateTime class.
(3) deprecated method not relevant.
(4) provide getter instead.

@kylekatarnls
Copy link
Author

Added from, fromNow, to, toNow via briannesbitt/Carbon#1385

@kylekatarnls
Copy link
Author

Lot of new methods added in briannesbitt/Carbon#1385

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment