How can I override date field validation? I'm overriding the date field to hide the "day" part with this code:

function MYMODULE_form_MYFORM_alter(&amp;$form, FormStateInterface $form_state, $form_id) {
  $form['#after_build'][] = 'MYMODULE_date_remove_day_after_build';
}

function MYMODULE_date_remove_day_after_build($form, &amp;$form_state) {
  $form['field_MYFIELD']['widget'][0]['value']['day']['#value'] = '15';
  $form['field_MYFIELD']['widget'][0]['value']['day']['#attributes']['class'][] = 'element-hidden';
  return $form;
}


This hides the day and allows the user to input the month and year.  If the field is required, everything is fine.

However, if the field is not required, and the user does not input any value on the form, then the form validation fails because the day of the date field has been set to 15, and the date module validation only accepts "every part (year + month + day) filled out" or "no part filled out."

So, on this specific field in my content type, I want to disable the date module's validation for the "day" alone-- or, I just want to disable validation for the entire date field.  How can I do that?
You can achieve this by prepending your own custom #element_validate function before Datelist::validateDatelist().

As in your question, you have to add an after_build function to access the individual parts (year, month, day) of the form element:

function MYMODULE_form_MYFORM_alter(&amp;$form, FormStateInterface $form_state, $form_id) {
  $form['#after_build'][] = 'MYMODULE_date_remove_day_after_build';
}


You can make the form element disappear by setting '#access' to FALSE.
Then prepend your custom #element_validate function to the array #element_validate on the element.

function MYMODULE_date_remove_day_after_build($form, &amp;$form_state) {
  $form['field_MYFIELD']['widget'][0]['value']['day']['#access'] = FALSE;
  array_unshift($form['field_MYFIELD']['widget'][0]['value']['#element_validate'], 'mymodule_date_set_day');
  return $form;
}


Then in your custom element validate function, unset everything if Year or Month are unset, otherwise, set the day.  Notice you have to create the object before passing it to Datelist::validateDatelist().

use Drupal\Core\Form\FormStateInterface;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Datetime\DrupalDateTime;

function mymodule_date_set_day(&amp;$element, FormStateInterface $form_state, &amp;$complete_form) {

  $input = NestedArray::getValue($form_state-&gt;getValues(), $element['#parents']);

  if (empty($input['year']) || empty($input['month'])) {
    $form_state-&gt;setValueForElement($element, []);
  }
  else {
    $input['day'] = "15";
    $timezone = !empty($element['#date_timezone']) ? $element['#date_timezone'] : NULL;
    $input['object'] = DrupalDateTime::createFromArray($input, $timezone);
    $form_state-&gt;setValueForElement($element, $input);
  }
}