Hello. On the d6 site i have a content type with two date field (d6 date module).
All the nodes where at least one of the date fields are not empty, are not beeing migrated.
Not just the field but the whole node.
In the upgrade log, i have error messages like this one:
ID sorgente 4148: Format date plugin could not transform "1965-00-00T00:00:00" using the format "Y-m-d\TH:i:s". Error: The created date does not match the input value.

In the d6 db, date values looks like this:

+------+--------------------------------------+---------------------------+
| nid  | field_libro_data_pubblicazione_value | field_data_prestito_value |
+------+--------------------------------------+---------------------------+
| 413 8| 1966-00-00T00:00:00                  | 2012-03-12T23:00:00       |
+------+--------------------------------------+---------------------------+

Can i solve this by editing the date format in the d6 db? Every suggestion is appreciated, thank you.

Comments

anairamzap’s picture

I've been struggling with a similar problem recently and found that the 'problem' here are those "00" values for Month and Day.

I added these lines in my custom source plugin:

$testdate = new DateTime("2020-00-00T00:00:00");
drush_print_r($testdate);

And when I run the migration, the result printed in terminal was: 1969-12-31 21:33:40 (just before the epoch :P)

So... what I think is that for D6 date fields set to only store YYYY, the field in mysql gets stored with all those zeros for the "missing" data.
And then, when Zend DateTime retrieves the fields, it gets confused with all those zeros and sets a date before the epoch.

I couldn't find any docs, only this issue archive that confirmed what I suspected.

Summarizing: I couldn't find any way to process those dates fields in a process plugin to be able to import them, so I ended up:

  1. Editing date field in my CT, adding month and day to the granularity.
  2. Modifying the 'wrong' dates using a VBO view (Execute arbitrary PHP script action) and some nasty php lines on D6 :(

Something similar to:

$odd_date = $object->field_my_date[0]['value'];
preg_match('/[0-9]{4}/', $odd_date , $results);
$corrected_date = $results[0];
$corrected_date = $curr_year;
$corrected_date .= '-01-01T00:00:00'; //Yeah, I know.
$object->field_my_date[0]['value'] = $corrected_date;
node_save($object);

Pasting these lines here in case is useful for someone else. Please backup your DB before!
Hopefully someone cleaver can help with the process plugin to avoid those steps :)

Cheers!
m

fonant’s picture

I was having trouble importing a D6 date field with month granularity into D8.

The default migration for the field is:

  field_month:
    plugin: sub_process
    source: field_month
    process:
      value:
        plugin: format_date
        from_format: 'Y-m-d\TH:i:s'
        to_format: 'Y-m-d\TH:i:s'
        source: value

But the from_format doesn't make a valid date if the day, matched by the "d", is zero.

I updated the migration config to have:

  field_month:
    plugin: sub_process
    source: field_month
    process:
      value:
        plugin: format_date
        from_format: 'Y-m-00\T00:00:00'
        to_format: 'Y-m-d\TH:i:s'
        source: value

And that works nicely.

http://www.fonant.com - Fonant Ltd - Quality websites

joseft40’s picture

Hi,

he used the development module to run the code and the tests. 

the problem is the month and day as they commented previously,
I have made several tests as you can see.

use Drupal\Core\Datetime\DrupalDateTime;

//tests performed
$date_value = "1966-00-00T00:00:00";
//$date_value = "1966-00-16T00:00:00";
//$date_value = "1966-01-00T00:00:00";
//$date_value = "1966-01-16T00:00:00";
//$date_value = "1966-02-00T00:00:00";
//$date_value = "1966-02-16T00:00:00";
//$date_value = "1966-08-00T00:00:00";
//$date_value = "1966-08-16T00:00:00";
//$date_value = "1966-11-16T00:00:00";
//$date_value = "1966-11-00T00:00:00";
//$date_value = "1966-12-16T00:00:00";
//$date_value = "1966-12-00T00:00:00";

//format drupal 6
$date_value = substr($date_value,0, -9);
$year = substr($date_value, 0 , -6);
$month = substr($date_value, 5, -3);
$day = substr($date_value, 8);
$date_value = $year . '-' . $month . '-' . $day;
ksm($date_value);

//format drupal 8
if ($day == "00") {
  $day = "01";
}
if ($month == "00") {
  $month = "01";
}
$date_value = $year . '-' . $month . '-' . $day;
$date = new DrupalDateTime($date_value);
$date = \Drupal::service('date.formatter')->format($date->getTimestamp(), 'custom', 'Y-M-d\TH:i:s', DATETIME_STORAGE_TIMEZONE);

ksm($date);
joseft40’s picture

You could implement this link during the migration process in a custom module and see what happens.

for example

use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Datetime\DrupalDateTime;

function your_module_custom_entity_presave(EntityInterface $entity) {
  if ($entity->getType() == 'your_content_type') {
    //format drupal 6
    $date_value = "1966-00-00T00:00:00";

    $date_value = substr($date_value,0, -9);
    $year = substr($date_value, 0 , -6);
    $month = substr($date_value, 5, -3);
    $day = substr($date_value, 8);
    $date_value = $year . '-' . $month . '-' . $day;

    //format drupal 8
    if ($day == "00") {
      $day = "01";
    }
    if ($month == "00") {
      $month = "01";
    }
    $date_value = $year . '-' . $month . '-' . $day;
    $date = new DrupalDateTime($date_value);

    $entity->set("created", $date->getTimestamp());
    //other example
    $entity->set("changed", $date->getTimestamp());
  }
}
steinmb’s picture

During D9 migration of one of my Drupal 7 sites. Note, It had previously been upgraded from D6 back in the days, I found a mix two date formats stored, this is a problem. The precision was set to only store year information. If you look at the process plugin format_date it accepts all formats DateTime::createFromFormat can take and you can locally test the dates like this. This is the two formats I found.

$date = DateTime::createFromFormat('Y-m-d H:i:s', '2010-01-01 00:00:00');
$date2 = DateTime::createFromFormat('Y-m-d\TH:i:s', '2010-01-01T00:00:00');
echo $date->format('Y-m-d') . PHP_EOL;
echo $date2->format('Y-m-d');

Since we did not care about time here we could grab only part of the string by using the substr plugin, and use that to populate the D9 field. This part was everything we wanted and more. You could also just grab year. Example:

  field_year_initiated:
    -
      plugin: sub_process
      source: field_year_initiated
      process:
        value:
          -
            plugin: substr
            start: 0
            length: 10
            source: value
          -
            plugin: format_date
            from_format: 'Y-m-d'
            to_format: Y-m-d

Stein Magne
http://smbjorklund.no