mirror of
https://github.com/usetrmnl/byos_laravel.git
synced 2026-01-14 15:37:53 +00:00
feat: add Liquid filter ordinalize
This commit is contained in:
parent
91e222f7a6
commit
c1786dfb6d
3 changed files with 128 additions and 0 deletions
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Liquid\Filters;
|
||||
|
||||
use App\Liquid\Utils\ExpressionUtils;
|
||||
use Carbon\Carbon;
|
||||
use Keepsuit\Liquid\Filters\FiltersProvider;
|
||||
|
||||
|
|
@ -22,4 +23,33 @@ class Date extends FiltersProvider
|
|||
|
||||
return Carbon::now()->subDays($days)->toDateString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date string with ordinal day (1st, 2nd, 3rd, etc.)
|
||||
*
|
||||
* @param string $dateStr The date string to parse
|
||||
* @param string $strftimeExp The strftime format string with <<ordinal_day>> placeholder
|
||||
* @return string The formatted date with ordinal day
|
||||
*/
|
||||
public function ordinalize(string $dateStr, string $strftimeExp): string
|
||||
{
|
||||
$date = Carbon::parse($dateStr);
|
||||
$ordinalDay = $date->ordinal('day');
|
||||
|
||||
// Convert strftime format to PHP date format
|
||||
$phpFormat = ExpressionUtils::strftimeToPhpFormat($strftimeExp);
|
||||
|
||||
// Split the format string by the ordinal day placeholder
|
||||
$parts = explode('<<ordinal_day>>', $phpFormat);
|
||||
|
||||
if (count($parts) === 2) {
|
||||
$before = $date->format($parts[0]);
|
||||
$after = $date->format($parts[1]);
|
||||
return $before . $ordinalDay . $after;
|
||||
}
|
||||
|
||||
// Fallback: if no placeholder found, just format normally
|
||||
return $date->format($phpFormat);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,4 +158,39 @@ class ExpressionUtils
|
|||
|
||||
return $expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert strftime format string to PHP date format string
|
||||
*
|
||||
* @param string $strftimeFormat The strftime format string
|
||||
* @return string The PHP date format string
|
||||
*/
|
||||
public static function strftimeToPhpFormat(string $strftimeFormat): string
|
||||
{
|
||||
$conversions = [
|
||||
'%A' => 'l', // Full weekday name
|
||||
'%a' => 'D', // Abbreviated weekday name
|
||||
'%B' => 'F', // Full month name
|
||||
'%b' => 'M', // Abbreviated month name
|
||||
'%Y' => 'Y', // Full year (4 digits)
|
||||
'%y' => 'y', // Year without century (2 digits)
|
||||
'%m' => 'm', // Month as decimal number (01-12)
|
||||
'%d' => 'd', // Day of month as decimal number (01-31)
|
||||
'%H' => 'H', // Hour in 24-hour format (00-23)
|
||||
'%I' => 'h', // Hour in 12-hour format (01-12)
|
||||
'%M' => 'i', // Minute as decimal number (00-59)
|
||||
'%S' => 's', // Second as decimal number (00-59)
|
||||
'%p' => 'A', // AM/PM
|
||||
'%P' => 'a', // am/pm
|
||||
'%j' => 'z', // Day of year as decimal number (001-366)
|
||||
'%w' => 'w', // Weekday as decimal number (0-6, Sunday is 0)
|
||||
'%U' => 'W', // Week number of year (00-53, Sunday is first day)
|
||||
'%W' => 'W', // Week number of year (00-53, Monday is first day)
|
||||
'%c' => 'D M j H:i:s Y', // Date and time representation
|
||||
'%x' => 'm/d/Y', // Date representation
|
||||
'%X' => 'H:i:s', // Time representation
|
||||
];
|
||||
|
||||
return str_replace(array_keys($conversions), array_values($conversions), $strftimeFormat);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,3 +30,66 @@ test('days_ago filter with large number works correctly', function (): void {
|
|||
|
||||
expect($filter->days_ago(100))->toBe($hundredDaysAgo);
|
||||
});
|
||||
|
||||
test('ordinalize filter formats date with ordinal day', function (): void {
|
||||
$filter = new Date();
|
||||
|
||||
expect($filter->ordinalize('2025-10-02', '%A, %B <<ordinal_day>>, %Y'))
|
||||
->toBe('Thursday, October 2nd, 2025');
|
||||
});
|
||||
|
||||
test('ordinalize filter handles datetime string with timezone', function (): void {
|
||||
$filter = new Date();
|
||||
|
||||
expect($filter->ordinalize('2025-12-31 16:50:38 -0400', '%A, %b <<ordinal_day>>'))
|
||||
->toBe('Wednesday, Dec 31st');
|
||||
});
|
||||
|
||||
test('ordinalize filter handles different ordinal suffixes', function (): void {
|
||||
$filter = new Date();
|
||||
|
||||
// 1st
|
||||
expect($filter->ordinalize('2025-01-01', '<<ordinal_day>>'))
|
||||
->toBe('1st');
|
||||
|
||||
// 2nd
|
||||
expect($filter->ordinalize('2025-01-02', '<<ordinal_day>>'))
|
||||
->toBe('2nd');
|
||||
|
||||
// 3rd
|
||||
expect($filter->ordinalize('2025-01-03', '<<ordinal_day>>'))
|
||||
->toBe('3rd');
|
||||
|
||||
// 4th
|
||||
expect($filter->ordinalize('2025-01-04', '<<ordinal_day>>'))
|
||||
->toBe('4th');
|
||||
|
||||
// 11th (special case)
|
||||
expect($filter->ordinalize('2025-01-11', '<<ordinal_day>>'))
|
||||
->toBe('11th');
|
||||
|
||||
// 12th (special case)
|
||||
expect($filter->ordinalize('2025-01-12', '<<ordinal_day>>'))
|
||||
->toBe('12th');
|
||||
|
||||
// 13th (special case)
|
||||
expect($filter->ordinalize('2025-01-13', '<<ordinal_day>>'))
|
||||
->toBe('13th');
|
||||
|
||||
// 21st
|
||||
expect($filter->ordinalize('2025-01-21', '<<ordinal_day>>'))
|
||||
->toBe('21st');
|
||||
|
||||
// 22nd
|
||||
expect($filter->ordinalize('2025-01-22', '<<ordinal_day>>'))
|
||||
->toBe('22nd');
|
||||
|
||||
// 23rd
|
||||
expect($filter->ordinalize('2025-01-23', '<<ordinal_day>>'))
|
||||
->toBe('23rd');
|
||||
|
||||
// 24th
|
||||
expect($filter->ordinalize('2025-01-24', '<<ordinal_day>>'))
|
||||
->toBe('24th');
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue