aeon-php/calendar
Aeon Calendar is a time management framework for PHP that makes working with dates, times, time zones, and intervals easier through a clean, object-oriented API, backed by solid testing and clear documentation with examples.
Installation
composer require aeon/calendar
No additional configuration is required—just autoload the package.
First Use Case: Creating a Date
use Aeon\Calendar\Date;
$date = Date::today(); // Creates an immutable Date object for today
echo $date->format('Y-m-d'); // Outputs: YYYY-MM-DD
Key Classes to Know
Date: Core immutable date object (year, month, day).Time: Immutable time object (hour, minute, second, timezone) with new methods like isMidnight() and isNotMidnight().DateTime: Combines Date and Time (immutable) with improved modify() method.Period: Represents a duration (e.g., 3 days, 2 weeks).Interval: Represents a recurring interval (e.g., every Monday).Month: Now supports __toString() and comparison via compareTo().Day, Year: New comparison support via compareTo().Where to Look First
src/Date.php, src/Time.php, src/DateTime.php, and src/Month.php for new methods.tests/ for usage examples and edge cases.$date = Date::fromFormat('Y-m-d', '2023-12-25');
$nextWeek = $date->add(Period::days(7)); // Returns new Date object
$nextWeek->format('Y-m-d'); // "2024-01-01"
add(Period): Adds a duration (e.g., days, months, years).subtract(Period): Subtracts a duration.modify(string $expression): Now fixed for reliability (e.g., '+1 month').$time = Time::fromFormat('H:i', '00:00', 'UTC');
$time->isMidnight(); // true
$time->isNotMidnight(); // false
$time = Time::fromFormat('H:i', '14:30', 'UTC');
$time->isMidnight(); // false
$time->isNotMidnight(); // true
isMidnight(): Checks if time is exactly 00:00:00.isNotMidnight(): Checks if time is not exactly 00:00:00.inTimezone(string $timezone): Returns a new Time object in the target timezone.$date1 = Date::fromFormat('Y-m-d', '2023-10-01');
$date2 = Date::fromFormat('Y-m-d', '2023-10-02');
$comparison = $date1->compareTo($date2); // Returns -1 (date1 is earlier)
$month1 = Month::fromDate($date1);
$month2 = Month::fromDate($date2);
$monthComparison = $month1->compareTo($month2); // Returns 0 (same month)
echo (string)$month1; // "October 2023" (via __toString())
compareTo(): Returns -1, 0, or 1 for comparison (works on Date, Time, DateTime, Month, Day, Year).__toString(): Now available for Month (e.g., "October 2023").$interval = Interval::daily();
$startDate = Date::fromFormat('Y-m-d', '2023-10-01');
$recurringDates = $interval->generate($startDate, Period::days(30)); // Array of Date objects
Interval::daily()Interval::weekly()Interval::monthly()Interval::yearly()$date = Date::fromFormat('Y-m-d', '2023-12-25');
$isWeekend = $date->isWeekend(); // true
$isBusinessDay = $date->isBusinessDay(); // false
$nextBusinessDay = $date->nextBusinessDay(); // Returns Date for 2023-12-26
isWeekend()isBusinessDay()nextBusinessDay()previousBusinessDay()Accessing Dates in Controllers/Requests
use Aeon\Calendar\Date;
public function show(Request $request) {
$eventDate = Date::fromFormat('Y-m-d', $request->input('date'));
// Use $eventDate in your logic
}
Storing Dates in the Database
Date::today()->format('Y-m-d') for storage (avoids timezone issues).protected $casts = [
'event_date' => Date::class, // Requires custom cast (see below)
];
use Aeon\Calendar\Date;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class DateCast implements CastsAttributes {
public function get($model, string $key, $value, array $attributes) {
return Date::fromFormat('Y-m-d', $value);
}
public function set($model, string $key, $value, array $attributes) {
return $value->format('Y-m-d');
}
}
Scheduling with Laravel
use Aeon\Calendar\Date;
use Aeon\Calendar\Time;
use Illuminate\Support\Facades\Schedule;
Schedule::call(function () {
$nextRun = Date::today()->add(Period::hours(1));
// Logic for scheduled task
})->hourly();
// Check if a scheduled time is midnight
$time = Time::fromFormat('H:i', '00:00', 'UTC');
if ($time->isMidnight()) {
// Handle midnight logic
}
API Responses
return response()->json([
'event_date' => Date::today()->format('Y-m-d H:i:s'),
'timezone' => Date::today()->getTimezone(),
'is_midnight' => Time::now()->isMidnight(),
]);
Month Comparison in API Logic
$currentMonth = Month::fromDate(Date::today());
$nextMonth = $currentMonth->add(Period::months(1));
return response()->json([
'current_month' => (string)$currentMonth, // "October 2023"
'next_month' => (string)$nextMonth, // "November 2023"
'comparison' => $currentMonth->compareTo($nextMonth), // -1
]);
Immutability Overhead
// Bad: Creates many intermediate objects
$finalDate = $date->add(Period::days(1))->subtract(Period::hours(1))->add(Period::minutes(30));
// Better: Use a single modification
$finalDate = $date->modify('+1 day -1 hour +30 minutes');
Timezone Confusion
Time) require explicit timezone handling. Defaults to system timezone.Time objects:
$time = Time::fromFormat('H:i', '12:00', 'UTC'); // Explicit timezone
Month/Year Arithmetic Edge Cases
$date = Date::fromFormat('Y-m-d', '2023-01-31');
$nextMonth = $date->
How can I help you explore Laravel packages today?