From 04b73d76195f2dc82fb929265312a7deaf3d061e Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Wed, 12 Jul 2017 22:04:23 -0500 Subject: [PATCH] Bugfix: The global s_get_timestamp() function is returning current time instead of requested time It looks like I copied the s_get_date() function and forgot to properly updated it (or got confused and forgot what I was working on). Either way, the implementation is incorrect and does not produce the correct timestamp. The function is rewritten to only support a time string to be formatted into a unix timestamp float. The base_defaults_global implementation is also not consistent with the one in reservation_defaults_global. The base_defaults_global is intended to be a default example implementation where reservation_defaults_global is an implementation specific to the reservation system. The postgresql default datetime string format is provided as a global constant in the database class for consistency. --- common/base/classes/base_database.php | 2 ++ common/base/classes/base_defaults_global.php | 39 +++++----------------- common/standard/classes/standard_users.php | 10 +++--- common/standard/paths/u/user_view.php | 3 +- .../reservation/reservation_defaults_global.php | 35 ++++--------------- 5 files changed, 23 insertions(+), 66 deletions(-) diff --git a/common/base/classes/base_database.php b/common/base/classes/base_database.php index 5193ada..dce9604 100644 --- a/common/base/classes/base_database.php +++ b/common/base/classes/base_database.php @@ -579,6 +579,8 @@ class c_base_database_connection_string extends c_base_return_string { * @require class c_base_session */ class c_base_database extends c_base_return { + const STANDARD_TIMESTAMP_FORMAT = 'Y-m-d h:i:s.uP'; + private $session; private $persistent; private $database; diff --git a/common/base/classes/base_defaults_global.php b/common/base/classes/base_defaults_global.php index 671cb27..58366e8 100644 --- a/common/base/classes/base_defaults_global.php +++ b/common/base/classes/base_defaults_global.php @@ -210,13 +210,12 @@ class c_base_defaults_global { * Get a timestamp, relative to UTC, with support for milliseconds and microseconds. * * Use this in place of strtotime() to ensure consistent timestamps in UTC format, with microseconds. + * To ensure proper support for microseconds (and milliseconds), both $string and $format must contain microseconds, even if it is set to 0. * * @param string $string - * The time string to get the timestamp of (relative to $timestmap if specified). - * @param int|float|null $timestamp - * (optional) If not NULL, a unix timestamp representing the timestamp to get the date string of. - * If NULL, the current session time is used. - * Timestamp is expected to be in UTC. + * The time string to get the timestamp of (relative to $timestamp if specified). + * @param string $format + * (optional) The format the $string is structured as. * * @return c_base_return_float * A timestamp in floating format. @@ -224,40 +223,18 @@ class c_base_defaults_global { * * @see: strtotime() */ - public static function s_get_timestamp($string, $timestamp = NULL) { + public static function s_get_timestamp($string, $format = 'Y/m/d h:i:s.u P') { if (!is_string($string)) { $error = c_base_error::s_log(NULL, array('arguments' => array(':{argument_name}' => 'string', ':{function_name}' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); return c_base_return_error::s_value(0.0, 'c_base_return_float', $error); } - if (!is_null($timestamp) && !is_float($timestamp) && !is_int($timestamp)) { - $error = c_base_error::s_log(NULL, array('arguments' => array(':{argument_name}' => 'timestamp', ':{function_name}' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); - return c_base_return_error::s_value(0.0, 'c_base_return_float', $error); - } - if (!is_null(self::$s_timezone)) { date_default_timezone_set('UTC'); } // To ensure support for microseconds (and milliseconds), datetime must be initialized woth microseconds. - if (is_null($timestamp)) { - $now = self::s_get_timestamp_session()->get_value_exact(); - $microseconds = (int) (($now - ((int) $now)) * 1000000); - - $date = new DateTime(date('Y/m/d h:i:s', (int) $now) . '.' . $microseconds . date(' P', (int) $now)); - unset($now); - } - else { - if (is_float($timestamp)) { - $microseconds = (int) (($timestamp - ((int) $timestamp)) * 1000000); - } - else { - $microseconds = 0; - } - - $date = new DateTime(date('Y/m/d h:i:s', (int) $timestamp) . '.' . $microseconds . date(' P', (int) $timestamp)); - } - unset($microseconds); + $date = DateTime::createFromFormat($format, $string); if (!($date instanceof DateTime)) { $error = c_base_error::s_log(NULL, array('arguments' => array(':{operation_name}' => 'date', ':{function_name}' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::OPERATION_FAILURE); @@ -265,7 +242,7 @@ class c_base_defaults_global { } $resulting_timestamp = $date->getTimestamp(); - if (!is_int($resulting_timestamp)) { + if (!is_int($resulting_timestamp) && !is_float($resulting_timestamp)) { $error = c_base_error::s_log(NULL, array('arguments' => array(':{operation_name}' => 'date->get_timestamp', ':{function_name}' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::OPERATION_FAILURE); return c_base_return_error::s_value(0.0, 'c_base_return_float', $error); } @@ -276,7 +253,7 @@ class c_base_defaults_global { date_default_timezone_set(self::$s_timezone); } - return c_base_return_string::s_new($formatted); + return c_base_return_float::s_new($resulting_timestamp); } /** diff --git a/common/standard/classes/standard_users.php b/common/standard/classes/standard_users.php index 70b3a2f..de854f4 100644 --- a/common/standard/classes/standard_users.php +++ b/common/standard/classes/standard_users.php @@ -266,11 +266,11 @@ class c_standard_users_user extends c_base_users_user { $this->is_roler = FALSE; } - $this->date_created = c_base_defaults_global::s_get_timestamp($columns[22])->get_value_exact(); - $this->date_changed = c_base_defaults_global::s_get_timestamp($columns[23])->get_value_exact(); - $this->date_synced = c_base_defaults_global::s_get_timestamp($columns[24])->get_value_exact(); - $this->date_locked = c_base_defaults_global::s_get_timestamp($columns[25])->get_value_exact(); - $this->date_deleted = c_base_defaults_global::s_get_timestamp($columns[26])->get_value_exact(); + $this->date_created = c_base_defaults_global::s_get_timestamp($columns[22], c_base_database::STANDARD_TIMESTAMP_FORMAT)->get_value_exact(); + $this->date_changed = c_base_defaults_global::s_get_timestamp($columns[23], c_base_database::STANDARD_TIMESTAMP_FORMAT)->get_value_exact(); + $this->date_synced = c_base_defaults_global::s_get_timestamp($columns[24], c_base_database::STANDARD_TIMESTAMP_FORMAT)->get_value_exact(); + $this->date_locked = c_base_defaults_global::s_get_timestamp($columns[25], c_base_database::STANDARD_TIMESTAMP_FORMAT)->get_value_exact(); + $this->date_deleted = c_base_defaults_global::s_get_timestamp($columns[26], c_base_database::STANDARD_TIMESTAMP_FORMAT)->get_value_exact(); if (isset($columns[27])) { $this->settings = json_decode($columns[27], TRUE); diff --git a/common/standard/paths/u/user_view.php b/common/standard/paths/u/user_view.php index fcf7f76..d5f7b18 100644 --- a/common/standard/paths/u/user_view.php +++ b/common/standard/paths/u/user_view.php @@ -7,6 +7,7 @@ require_once('common/base/classes/base_error.php'); require_once('common/base/classes/base_return.php'); require_once('common/base/classes/base_path.php'); +require_once('common/base/classes/base_database.php'); require_once('common/standard/classes/standard_path.php'); @@ -615,7 +616,7 @@ class c_standard_path_user_view extends c_standard_path { $this->log_severity = (int) $columns[5]; $this->log_facility = (int) $columns[6]; $this->log_details = json_decode($columns[7], TRUE); - $this->log_date = c_base_defaults_global::s_get_timestamp($columns[8])->get_value_exact(); + $this->log_date = c_base_defaults_global::s_get_timestamp($columns[8], c_base_database::STANDARD_TIMESTAMP_FORMAT)->get_value_exact(); $this->request_client = (string) $columns[9]; $this->response_code = (int) $columns[10]; diff --git a/program/reservation/reservation_defaults_global.php b/program/reservation/reservation_defaults_global.php index 1810843..c7b2c10 100644 --- a/program/reservation/reservation_defaults_global.php +++ b/program/reservation/reservation_defaults_global.php @@ -210,13 +210,12 @@ class c_base_defaults_global { * Get a timestamp, relative to UTC, with support for milliseconds and microseconds. * * Use this in place of strtotime() to ensure consistent timestamps in UTC format, with microseconds. + * To ensure proper support for microseconds (and milliseconds), both $string and $format must contain microseconds, even if it is set to 0. * * @param string $string - * The time string to get the timestamp of (relative to $timestmap if specified). - * @param int|float|null $timestamp - * (optional) If not NULL, a unix timestamp representing the timestamp to get the date string of. - * If NULL, the current session time is used. - * Timestamp is expected to be in UTC. + * The time string to get the timestamp of (relative to $timestamp if specified). + * @param string $format + * (optional) The format the $string is structured as. * * @return c_base_return_float * A timestamp in floating format. @@ -224,40 +223,18 @@ class c_base_defaults_global { * * @see: strtotime() */ - public static function s_get_timestamp($string, $timestamp = NULL) { + public static function s_get_timestamp($string, $format = 'Y/m/d h:i:s.u P') { if (!is_string($string)) { $error = c_base_error::s_log(NULL, array('arguments' => array(':{argument_name}' => 'string', ':{function_name}' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); return c_base_return_error::s_value(0.0, 'c_base_return_float', $error); } - if (!is_null($timestamp) && !is_float($timestamp) && !is_int($timestamp)) { - $error = c_base_error::s_log(NULL, array('arguments' => array(':{argument_name}' => 'timestamp', ':{function_name}' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT); - return c_base_return_error::s_value(0.0, 'c_base_return_float', $error); - } - if (!is_null(self::$s_timezone)) { date_default_timezone_set('UTC'); } // To ensure support for microseconds (and milliseconds), datetime must be initialized woth microseconds. - if (is_null($timestamp)) { - $now = self::s_get_timestamp_session()->get_value_exact(); - $microseconds = (int) (($now - ((int) $now)) * 1000000); - - $date = new DateTime(date('Y/m/d h:i:s', (int) $now) . '.' . $microseconds . date(' P', (int) $now)); - unset($now); - } - else { - if (is_float($timestamp)) { - $microseconds = (int) (($timestamp - ((int) $timestamp)) * 1000000); - } - else { - $microseconds = 0; - } - - $date = new DateTime(date('Y/m/d h:i:s', (int) $timestamp) . '.' . $microseconds . date(' P', (int) $timestamp)); - } - unset($microseconds); + $date = DateTime::createFromFormat($format, $string); if (!($date instanceof DateTime)) { $error = c_base_error::s_log(NULL, array('arguments' => array(':{operation_name}' => 'date', ':{function_name}' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::OPERATION_FAILURE); -- 1.8.3.1