From f07dbf7439e2c51cbad228e73be53cc6effa56b2 Mon Sep 17 00:00:00 2001 From: nathangray Date: Fri, 2 Feb 2018 11:37:02 -0700 Subject: [PATCH] Attempt to prefer user's date format when parsing date from a string. Should fix merging into spreadsheet problems with certain date formats (dd/mm/yyyy) --- api/src/DateTime.php | 53 ++++++++++++++++++++++++++++++++++++++- api/src/Storage/Merge.php | 29 +-------------------- 2 files changed, 53 insertions(+), 29 deletions(-) diff --git a/api/src/DateTime.php b/api/src/DateTime.php index f327b2ad2f..7f2eaec8ba 100644 --- a/api/src/DateTime.php +++ b/api/src/DateTime.php @@ -467,7 +467,8 @@ class DateTime extends \DateTime { try { - $time = new DateTime($time); + // Try user format first + $time = static::createFromUserFormat($time); } catch(\Exception $e) { @@ -478,6 +479,56 @@ class DateTime extends \DateTime return $time->format($type); } + /** + * Some user formats are conflicting and cannot be reliably parsed by the + * normal means. Here we agressively try various date formats (based on + * user's date preference) to coerce a troublesome date into a DateTime. + * + * ex: 07/08/2018 could be DD/MM/YYYY or MM/DD/YYYY + * + * Rather than trust DateTime to guess right based on its settings, we use + * the user's date preference to resolve the ambiguity. + * + * @param string $time + * @return DateTime or null + */ + public static function createFromUserFormat($time) + { + $date = null; + + // If numeric, just let normal constructor do it + if(is_numeric($time)) + { + return new DateTime($time); + } + + // Various date formats in decreasing preference + $formats = array( + '!'.static::$user_dateformat . ' ' .static::$user_timeformat.':s', + '!'.static::$user_dateformat . '*' .static::$user_timeformat.':s', + '!'.static::$user_dateformat . '* ' .static::$user_timeformat, + '!'.static::$user_dateformat . '*', + '!'.static::$user_dateformat, + '!Y-m-d\TH:i:s' + ); + // Try the different formats, stop when one works + foreach($formats as $f) + { + try { + $date = static::createFromFormat( + $f, + $time, + static::$user_timezone + ); + if($date) break; + } catch (\Exception $e) { + + } + } + // Need correct class, createFromFormat() gives parent + return new DateTime($date ? $date : $time); + } + /** * Setter for user timezone, should be called after reading user preferences * diff --git a/api/src/Storage/Merge.php b/api/src/Storage/Merge.php index 4be334770e..20f873b95d 100644 --- a/api/src/Storage/Merge.php +++ b/api/src/Storage/Merge.php @@ -1288,34 +1288,7 @@ abstract class Merge $field = preg_quote($field, '/'); if($values[$key]) { - if(!is_numeric($values[$key])) - { - // Try the different formats, stop when one works - foreach($formats as $f) - { - try { - $date = Api\DateTime::createFromFormat( - $f, - $values[$key], - Api\DateTime::$user_timezone - ); - if($date) break; - } catch (\Exception $e) { - - } - } - if(!$date) - { - // Couldn't get a date out of it... skip it - trigger_error("Unable to parse date $key = '{$values[$key]}' - left as text", E_USER_NOTICE); - unset($names[$idx]); - continue; - } - } - else - { - $date = new Api\DateTime($values[$key]); - } + $date = Api\DateTime::createFromUserFormat($values[$key]); if($mimetype == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || $mimetype == 'application/vnd.ms-excel.sheet.macroenabled.12')//Excel WTF {