Date Granularity in PHP and Drupal. Or where did this 11-30 come from?

Submitted by John on Tue, 05/17/2016 - 08:12

TL;DR: Why are my dates being converted to November 30th in PHP? Because zero is an invalid month and day.

One thing that strikes me odd is how to handle dates with wide granularities in PHP, and Drupal as usual. I came across this problem in a content migration project. In Drupal 6, a date field that was only granular to the year would like something like this:

2016-00-00T00:00:00

However, a date field in D6 might look like this:

2016-01-01 00:00:00 

See the difference? The first is technically an invalid date. The seocond is a valid one, marking a specific time. There certainly may be some variation in the way a field is set up here. But, If you attempt to migrate this using the Migrate module from a D6 site to a D7 site, it will cause the date to revert to a valid one that might look like this:

2015-11-30 05:00:00

Where did that come from?!?! This might seem totally arbitrary at first, but upon deeper investigation, you may run across this Stack Overflow post. What happens is that the 00-00 day-month combination is invalid, and is interpreted as the next valid date subtracted by one. So January, minus a month becomes december, but then day 00, minus one, becomes the last day of the previous month. So 01-01 minus 1 month == 12-01, minus 1 day becomes 11-30.

Additionally, since the original date itself was configured not to handle any timezone, however, while being imported, the timezone gets interpreted as UTC.

To address the invalid date issue, I added callback to my migration's field mapping for that date field.

  public function fixDate($value) {

    $date = new DateTime($value);

    // Add 1 month and 2 day to make this a valid date. (11-30 => 01-01)
    $interval = new DateInterval('P1M2D');
    $date->add($interval);

    // This is still going to come out as 20XX-01-01 05:00:00
    return $date->format('Y-m-d H:i');

  }

This adds 1 month and two days to the date value (since December has 31 days). which was already interpreted as 11-30.

 

Tags