herrera-io/date-interval
Extends PHP’s DateInterval with handy conversions: turn intervals into ISO interval specs and seconds, and recreate intervals from seconds. Useful for normalizing and serializing durations (e.g., P2H <-> 7200).
Installation:
composer require herrera-io/date-interval:^1.0
Ensure ext-bcmath is enabled in your PHP environment (required for toSeconds()).
First Use Case:
Convert a DateInterval to a string spec or seconds for API responses, database storage, or calculations:
use Herrera\DateInterval\DateInterval;
// Create from ISO 8601 spec
$interval = new DateInterval('P1Y2M3DT4H5M6S');
echo $interval->toSpec(); // "P1Y2M3DT4H5M6S"
// Convert to seconds for arithmetic
$seconds = $interval->toSeconds();
echo $seconds; // 32578066 (total seconds)
// Static alternative
echo DateInterval::toSeconds(new \DateInterval('P1D')); // 86400
Where to Look First:
toSpec() and toSeconds().API Responses:
Serialize DateInterval objects to ISO 8601 specs for consistency:
return response()->json([
'duration' => (new DateInterval('P1M'))->toSpec(),
]);
Database Storage:
Store intervals as seconds in a bigint column (e.g., for PostgreSQL INTERVAL compatibility):
$interval = new DateInterval('P2W');
$model->duration_seconds = $interval->toSeconds();
$model->save();
Scheduling:
Parse cron-like intervals into seconds for Laravel’s schedule:
$interval = new DateInterval('P1DT2H');
$seconds = $interval->toSeconds();
// Use $seconds in custom scheduling logic
Carbon Bridge:
Extend Carbon’s Interval class to use this package’s methods:
use Herrera\DateInterval\DateInterval;
class CarbonInterval extends \Carbon\CarbonInterval {
public function toSpec(): string {
return (new DateInterval($this->interval))->toSpec();
}
}
Input Validation:
Validate ISO 8601 specs before creating DateInterval objects:
use Herrera\DateInterval\DateInterval;
$spec = request('interval');
try {
$interval = new DateInterval($spec);
} catch (\InvalidArgumentException $e) {
return response()->json(['error' => 'Invalid interval'], 400);
}
Time-Based Policies:
Use toSeconds() for rate limiting or throttling:
$window = new DateInterval('PT1H');
$windowSeconds = $window->toSeconds();
// Compare against current timestamp in seconds
Legacy System Interop:
Convert between this package and native DateInterval:
$nativeInterval = new \DateInterval('P1D');
$extendedInterval = new DateInterval($nativeInterval->format('%aD%hH%iM%sS'));
Service Provider Binding: Bind the package to Laravel’s container for dependency injection:
$this->app->bind(\DateInterval::class, function ($app) {
return new \Herrera\DateInterval\DateInterval(...);
});
Facade for Convenience: Create a facade to simplify usage:
// app/Facades/Interval.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
use Herrera\DateInterval\DateInterval;
class Interval extends Facade {
protected static function getFacadeAccessor() {
return DateInterval::class;
}
}
Register in AppServiceProvider:
Facade::clearResolvedInstanceFor('interval');
Testing: Mock the package in unit tests:
$this->partialMock(DateInterval::class, ['toSeconds'])
->shouldReceive('toSeconds')
->andReturn(3600);
bcmath Dependency:
toSeconds() requires the bcmath extension, which may not be enabled by default.php.ini or Dockerfile:
extension=bcmath
gmp or math extensions if bcmath is unavailable (check the wiki).Timezone Sensitivity:
DateInterval calculations are timezone-agnostic, but toSeconds() may behave unexpectedly with DST transitions.$interval = new DateInterval('P1D');
$interval->setTimezone(new \DateTimeZone('UTC'));
Fractional Seconds:
toSeconds() truncates fractional seconds (e.g., PT0.5S becomes 0).DateTime for sub-second precision or round manually:
$seconds = round($interval->toSeconds(), 2);
Negative Intervals:
-P1D) may not work as expected with toSeconds().if ($interval->invert === 1) {
$seconds = -$interval->toSeconds();
}
Archived Package Risks:
carbon/carbon for new projects.Invalid Specs:
InvalidArgumentException when creating DateInterval.createFromFormat():
if (!preg_match('/^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)(S|s))?)?$/', $spec)) {
throw new \InvalidArgumentException('Invalid interval spec');
}
Unexpected Seconds:
toSeconds() returns incorrect values.$expected = (24 * 60 * 60) + (3 * 60 * 60); // 2 days + 3 hours
$actual = (new DateInterval('P2DT3H'))->toSeconds();
Serialization Errors:
DateInterval fails to serialize/deserialize (e.g., in queues).$interval = new DateInterval('P1D');
$data = ['interval_spec' => $interval->toSpec()];
Laravel Cache:
DateInterval objects may lose precision.Cache::put('interval', $interval->toSpec(), $interval->toSeconds());
Database Storage:
DateInterval objects directly in databases (e.g., JSON) may cause issues.$model->interval = $interval->toSpec(); // or $interval->toSeconds()
Custom Interval Classes:
Extend Herrera\DateInterval\DateInterval for domain-specific logic:
class BillingInterval extends DateInterval {
public function toBillingCycles(): int {
return $this->toSeconds() / (60 * 60 * 24); // Simplified
}
}
Carbon Integration:
Add methods to Carbon’s Interval class:
\Carbon\CarbonInterval::macro('toSpec',
How can I help you explore Laravel packages today?