Skip to content

wickedbyte/carbon-migration-rector-rules

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Carbon 2 → Carbon 3 Rector Migration Rules

This project is an independently maintained fork of phoneburner/carbon-migration-rector-rules, originally released under the MIT license, by the original project authors. This fork is neither affiliated with nor endorsed by PhoneBurner.

Automated Rector rules to migrate your PHP codebase from Carbon 2 to Carbon 3, with special attention to codebases that do NOT use UTC as the default timezone.

Overview

Carbon 3 introduced several breaking changes. Some are simple renames, but others silently change behavior (like createFromTimestamp defaulting to UTC, or diffIn* returning signed floats). These rules automate as much of the migration as possible and leave TODO comments for anything that requires manual judgment.

Installation

# Install Rector if you haven't already
composer require rector/rector --dev

# Copy the rules into your project
cp -r src/Rector /path/to/your/project/utils/rector/src/Rector
cp -r src/Set /path/to/your/project/utils/rector/src/Set

Add to your composer.json:

{
    "autoload-dev": {
        "psr-4": {
            "Carbon3Rector\\": "utils/rector/src"
        }
    }
}

Then:

composer dump-autoload

Usage

Create or update your rector.php:

<?php

use Carbon3Rector\Set\CarbonMigrationRules;
use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withPaths([
        __DIR__ . '/src',
        __DIR__ . '/app',
    ])
    ->withRules(CarbonMigrationRules::ALL);

Run:

# Preview changes
vendor/bin/rector process --dry-run

# Apply changes
vendor/bin/rector process

Rules Included

1. CarbonCreateFromTimestampToExplicitTimezoneRector

Severity Critical (silent behavior change)

Carbon 3 changed createFromTimestamp() default timezone from date_default_timezone_get() to "UTC". For non-UTC codebases, this silently changes every timestamp conversion.

-$date = Carbon::createFromTimestamp($timestamp);
+$date = Carbon::createFromTimestamp($timestamp, date_default_timezone_get());

2. CarbonCreateFromTimestampMsToExplicitTimezoneRector

Severity Critical (silent behavior change)

Same as above but for createFromTimestampMs().

-$date = Carbon::createFromTimestampMs($ms);
+$date = Carbon::createFromTimestampMs($ms, date_default_timezone_get());

3. CarbonDiffInMethodsToExplicitCastRector

Severity Critical (silent behavior change)

diffIn* methods changed from returning positive int to returning signed float. This rule wraps calls in (int) abs(...) to preserve Carbon 2 behavior.

-$seconds = $a->diffInSeconds($b);
+$seconds = (int) abs($a->diffInSeconds($b));

 // If already using absolute=true, just casts to int:
-$hours = $a->diffInHours($b, true);
+$hours = (int) $a->diffInHours($b, true);

Covered methods: diffInYears, diffInMonths, diffInWeeks, diffInDays, diffInDaysFiltered, diffInHours, diffInMinutes, diffInSeconds, diffInMicroseconds, diffInMilliseconds, diffInWeekdays, diffInWeekendDays, diffInRealHours, diffInRealMinutes, diffInRealSeconds, diffInRealMicroseconds, diffInRealMilliseconds

4. CarbonFalseReturnToNullRector

Severity Medium (will cause type errors)

create(), createFromFormat(), createFromIsoFormat(), createFromLocaleFormat(), and createFromLocaleIsoFormat() now return null instead of false on failure.

-if (Carbon::createFromFormat('Y-m-d', $input) === false) {
+if (Carbon::createFromFormat('Y-m-d', $input) === null) {

5. CarbonIsSameWithoutParamToIsCurrentRector

Severity Medium (will throw exception)

isSame*() methods no longer accept zero arguments. The Carbon 2 behavior (compare to "now") is now isCurrent*().

-$date->isSameDay();
+$date->isCurrentDay();

-$date->isSameMonth();
+$date->isCurrentMonth();

6. CarbonMinMaxValueToStartEndOfTimeRector

Severity Medium (method removed)

minValue() and maxValue() were removed. Replaced by CarbonImmutable-only methods.

-$min = Carbon::minValue();
+$min = CarbonImmutable::startOfTime();

-$max = Carbon::maxValue();
+$max = CarbonImmutable::endOfTime();

7. CarbonNamedArgTzToTimezoneRector

Severity Medium (will cause error)

All named argument tz: parameters were renamed to timezone:.

-Carbon::create(2024, 1, 1, tz: 'UTC');
+Carbon::create(2024, 1, 1, timezone: 'UTC');

8. CarbonFormatLocalizedToIsoFormatRector

Severity Medium (method removed)

formatLocalized() (which relied on OS strftime()) was removed. Replaced by isoFormat() with automatic strftime→isoFormat token conversion.

-$date->formatLocalized('%A %d %B %Y');
+$date->isoFormat('dddd DD MMMM YYYY');

Adds TODO comments when format strings contain tokens that can't be automatically converted or when the format is dynamic.

9. CarbonSetUtf8RemovalRector

Severity Low (method removed)

Removes setUtf8() calls which no longer exist.

-Carbon::setUtf8(true);
 $date = Carbon::now();

10. CarbonSetWeekStartsAtRemovalRector

Severity Medium (method removed, needs manual migration)

Removes setWeekStartsAt() / setWeekEndsAt() and adds TODO comments with migration guidance.

-Carbon::setWeekStartsAt(Carbon::MONDAY);
+// TODO: [Carbon 3 migration] setWeekStartsAt() was removed in Carbon 3.
+// Pass the day explicitly to startOfWeek(\Carbon\WeekDay::Monday) or use locale-based week start.

After Running Rector

After applying the automated rules, review the MIGRATION_CHECKLIST.md file included in this package for things that need manual inspection.

Search your codebase for TODO: [Carbon 3 migration] to find all spots that need manual review.

Running Individual Rules

You can run specific rules instead of the full set:

use WickedByte\CarbonMigrationRectorRules\CarbonDiffInMethodsToExplicitCastRector;
use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withRules([
        CarbonDiffInMethodsToExplicitCastRector::class,
    ]);

Regex to Find Remaining Issues

After running Rector, use these regex patterns to find any remaining issues:

# Find diffIn* calls that might not have been caught
grep -rn 'diffIn\(Seconds\|Minutes\|Hours\|Days\|Weeks\|Months\|Years\)' src/

# Find createFromTimestamp without explicit timezone
grep -rn 'createFromTimestamp(' src/ | grep -v 'date_default_timezone_get'

# Find any remaining false comparisons with Carbon create methods
grep -rn 'createFromFormat.*=== false\|=== false.*createFromFormat' src/

# Find any remaining formatLocalized calls
grep -rn 'formatLocalized' src/

# Find comparison methods that might receive null/bool
grep -rn '->eq(\|->gt(\|->lt(\|->gte(\|->lte(\|->ne(' src/

License

MIT

About

Automated Rector rules to migrate your PHP codebase from Carbon 2 to Carbon 3, with special attention for handling default time zones other than UTC.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • PHP 89.0%
  • Makefile 7.6%
  • Dockerfile 3.4%