Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldTypes

DateFieldType::resolve_constraint │ private │ WC 1.0

Resolves a date field min/max constraint to a YYYY-MM-DD date in the store's timezone.

Durations are resolved at read time, so they follow the current date rather than freezing into whatever markup a page cache stored.

We use DateInterval to resolve durations but it has 2 issues that we must solve here:

  1. Negative constraints are not supported with this version, so we must account for them ourselves.
  2. DateInterval has an inconsistent behavior compared to ISO 8601-2 in which adding a month to a date equals adding 31 days instead of a calendar month, resulting in P1M after Jan 31 giving you Mar 3 instead of Feb 28.

Метод класса: DateFieldType{}

Хуков нет.

Возвращает

string. The resolved date.

Использование

// private - только в коде основоного (родительского) класса
$result = $this->resolve_constraint( $value, $reference ): string;
$value(строка) (обязательный)
The constraint, as validated and normalized at registration.
$reference(DateTimeInterface|null)
Date a duration is relative to.
По умолчанию: today in the store timezone

Код DateFieldType::resolve_constraint() WC 11.2.2

private function resolve_constraint( string $value, $reference = null ): string {
	if ( $this->is_absolute_date( $value ) ) {
		return $value;
	}

	$sign     = '-' === $value[0] ? -1 : 1;
	$interval = self::parse_duration( ltrim( $value, '-' ) );
	$today    = new \DateTimeImmutable( $reference ? $reference->format( 'Y-m-d' ) : 'today', wp_timezone() );

	// Handles the DateInterval bug in which months days overflow to the next month instead of staying in the current month.
	// P1M to Jan 31 gives you Mar 3 instead of Feb 28.
	// So we deconstruct the period into years, months, and days, and then add them back separately.
	$months = $sign * ( $interval->y * 12 + $interval->m );
	$days   = $sign * $interval->d;
	// Adding x months to today and asking for the last day of that month, then clamping the day to today if it exceeds it.
	$end_of_month = $today->modify( sprintf( 'last day of %+d months', $months ) );
	$resolved     = $end_of_month->setDate(
		(int) $end_of_month->format( 'Y' ),
		(int) $end_of_month->format( 'n' ),
		// Asking for min will get us the correct end of month if we're about to overflow, or the actual date.
		// Because adding P1M to Jan 17 should give you Feb 17 but adding P1M to Jan 28-31 should give you Feb 28 (or Feb 29 on leap years).
		min( (int) $today->format( 'j' ), (int) $end_of_month->format( 'j' ) )
	);

	// Add the days back from the original interval.
	return $resolved->modify( sprintf( '%+d days', $days ) )->format( 'Y-m-d' );
}