From 0bbdc4f3d664a425329d871a2a00e2528e31c8af Mon Sep 17 00:00:00 2001 From: Tungnx Date: Fri, 3 Jul 2026 19:05:55 +0700 Subject: [PATCH 1/2] ~ Create new Class handle DateTime --- inc/Helpers/LPDateTime.php | 120 ++++++++++++++++++++++++++++++++ inc/custom-post-types/order.php | 3 + 2 files changed, 123 insertions(+) create mode 100644 inc/Helpers/LPDateTime.php diff --git a/inc/Helpers/LPDateTime.php b/inc/Helpers/LPDateTime.php new file mode 100644 index 0000000000..efeba7872b --- /dev/null +++ b/inc/Helpers/LPDateTime.php @@ -0,0 +1,120 @@ +raw_date = gmdate( self::FORMAT_MYSQL, $time ); + $this->is_local_wp = $is_local_wp; + } + + public function get_raw_date() { + return $this->raw_date; + } + + /** + * Format date time to string + * + * @param string $format + * @param bool $to_local + * @return string + */ + public function format( string $format = '', bool $to_local = false ): string { + $option_date_format = get_option( 'date_format' ); + $option_time_format = get_option( 'time_format' ); + + if ( $to_local ) { + // Convert to local timezone + $timezone = wp_timezone(); + } else { + // Keep sample date time, only change format + $timezone = new DateTimeZone( 'UTC' ); + } + + switch ( $format ) { + case self::FORMAT_MYSQL: + return wp_date( $this->get_raw_date(), $timezone ); + case self::FORMATE_I18N_DATE: + return wp_date( $option_date_format, $this->get_timestamp() ); + case self::FORMAT_I18N_DATE_TIME: + return wp_date( + $option_date_format . ' ' . $option_time_format, + $this->get_timestamp(), + $timezone + ); + case self::FORMAT_I18N_DATE_TIME_TIMEZONE: + return sprintf( + '%s %s', + wp_date( + $option_date_format . ' ' . $option_time_format, + $this->get_timestamp(), + $timezone + ), + wp_timezone_string() + ); + case self::FORMAT_HUMAN: + return sprintf( + __( '%s ago', 'learnpress' ), + human_time_diff( $this->get_timestamp(), time() ) + ); + default: + return gmdate( $format, $this->get_timestamp() ); + } + } + + /** + * Get timestamp of Date. + * + * @return int + */ + public function get_timestamp(): int { + return strtotime( $this->raw_date ); + } +} diff --git a/inc/custom-post-types/order.php b/inc/custom-post-types/order.php index 2bd8cdd039..46d6f3799d 100644 --- a/inc/custom-post-types/order.php +++ b/inc/custom-post-types/order.php @@ -12,6 +12,7 @@ use LearnPress\Databases\PostDB; use LearnPress\Filters\OrderPostFilter; use LearnPress\Filters\PostFilter; +use LearnPress\Helpers\LPDateTime; use LearnPress\Models\PostModel; use LearnPress\Models\UserItems\UserCourseModel; use LearnPress\Models\UserItems\UserItemModel; @@ -654,6 +655,8 @@ public function columns_content( $column, $post_id = 0 ) { esc_html( $time_display ) ); + $m = new LPDateTime( '2026-07-03 13:00:00' ); + echo '
' . $m->format( LPDateTime::FORMAT_I18N_DATE_TIME_TIMEZONE, true ) . '
'; break; case 'order_items': do_action( 'learn-press/admin/order-items/layout', $lp_order ); From a75831d2d33b9abd78526e4ab4cc849e23d821f1 Mon Sep 17 00:00:00 2001 From: tungnx89 Date: Sun, 5 Jul 2026 18:40:25 +0700 Subject: [PATCH 2/2] = 4.4.2 = ~ Tweak: LPDateTime ~ Apply LPDateTime for Order --- inc/Helpers/LPDateTime.php | 265 +++++++++++++++++++++++++------- inc/custom-post-types/order.php | 20 ++- 2 files changed, 222 insertions(+), 63 deletions(-) diff --git a/inc/Helpers/LPDateTime.php b/inc/Helpers/LPDateTime.php index efeba7872b..99a7b45a50 100644 --- a/inc/Helpers/LPDateTime.php +++ b/inc/Helpers/LPDateTime.php @@ -4,8 +4,6 @@ use DateTime; use DateTimeZone; -use LP_Debug; -use Throwable; defined( 'ABSPATH' ) || exit; @@ -20,12 +18,11 @@ class LPDateTime { /** * Format date by config WP. */ - const FORMATE_I18N_DATE = 'i18n_date'; + const FORMAT_I18N_DATE = 'i18n_date'; /** * Format date time by config WP. */ - const FORMAT_I18N_DATE_TIME = 'i18n_date_time'; - const FORMAT_I18N_DATE_TIME_TIMEZONE = 'i18n_date_time_timezone'; + const FORMAT_I18N_DATE_TIME = 'i18n_date_time'; /** * Format date time Human. */ @@ -36,85 +33,243 @@ class LPDateTime { * * @var string $raw_date . */ - protected $raw_date = null; - protected $is_local_wp = false; + protected $raw_date = ''; /** * Constructor. * - * @param string|int $date - * @param bool $is_local_wp Is timezone setting on the WP. Default is false is GMT (UTC+0) + * @param string $date_gmt Date must be in GMT (UTC+0). */ - public function __construct( string $date = '', bool $is_local_wp = false ) { - $time = strtotime( $date ); - if ( empty( $date ) ) { + public function __construct( string $date_gmt = '' ) { + $time = strtotime( $date_gmt ); + if ( empty( $date_gmt ) ) { $time = time(); } - $this->raw_date = gmdate( self::FORMAT_MYSQL, $time ); - $this->is_local_wp = $is_local_wp; + $this->raw_date = (string) gmdate( self::FORMAT_MYSQL, $time ); } - public function get_raw_date() { + /** + * Get raw date. + * + * @return string + */ + public function get_raw_date(): string { return $this->raw_date; } /** - * Format date time to string + * Get timestamp of Date. * - * @param string $format - * @param bool $to_local - * @return string + * @return int + */ + public function get_timestamp(): int { + return strtotime( $this->get_raw_date() ); + } + + /** + * Format the date/time into a string. + * + * - $type_convert = 'keep' preserves the GMT/UTC time. + * - $type_convert = 'gmt_to_local' converts to the site's local timezone. + * + * @param string $format Output format (MYSQL, I18N_DATE, I18N_DATE_TIME, HUMAN, or a custom format string). + * @param string $type_convert Timezone conversion mode: keep|gmt_to_local. + * @param bool $return_has_timezone Whether to append the timezone name to the output. + * + * @return string The formatted date/time string. */ - public function format( string $format = '', bool $to_local = false ): string { + public function format( string $format = '', string $type_convert = 'keep', bool $return_has_timezone = false ): string { + $string = ''; $option_date_format = get_option( 'date_format' ); $option_time_format = get_option( 'time_format' ); - - if ( $to_local ) { - // Convert to local timezone - $timezone = wp_timezone(); - } else { - // Keep sample date time, only change format - $timezone = new DateTimeZone( 'UTC' ); - } + $timestamp = $this->get_timestamp(); + $timezone = 'gmt_to_local' === $type_convert ? wp_timezone() : new DateTimeZone( 'UTC' ); switch ( $format ) { case self::FORMAT_MYSQL: - return wp_date( $this->get_raw_date(), $timezone ); - case self::FORMATE_I18N_DATE: - return wp_date( $option_date_format, $this->get_timestamp() ); + $string = wp_date( self::FORMAT_MYSQL, $timestamp, $timezone ); + break; + case self::FORMAT_I18N_DATE: + $string = wp_date( $option_date_format, $timestamp, $timezone ); + break; case self::FORMAT_I18N_DATE_TIME: - return wp_date( - $option_date_format . ' ' . $option_time_format, - $this->get_timestamp(), - $timezone - ); - case self::FORMAT_I18N_DATE_TIME_TIMEZONE: - return sprintf( - '%s %s', - wp_date( - $option_date_format . ' ' . $option_time_format, - $this->get_timestamp(), - $timezone - ), - wp_timezone_string() - ); + $string = wp_date( $option_date_format . ' ' . $option_time_format, $timestamp, $timezone ); + break; case self::FORMAT_HUMAN: - return sprintf( - __( '%s ago', 'learnpress' ), - human_time_diff( $this->get_timestamp(), time() ) - ); + $string = sprintf( __( '%s ago', 'learnpress' ), human_time_diff( $timestamp, time() ) ); + break; default: - return gmdate( $format, $this->get_timestamp() ); + $string = wp_date( $format, $timestamp, $timezone ); + break; } + + if ( $return_has_timezone ) { + $string .= ' ' . $timezone->getName(); + } + + return $string; } /** - * Get timestamp of Date. + * Display date human time diff. + * 1. Show number days, hours if >= 1 days + * 2. Show number hours, seconds if >= 1 hours + * 3. Show number seconds if < 1 hours + * Clone from LP_Datetime::format_human_time_diff since 4.0.3 * - * @return int + * @param DateTime $date_start + * @param DateTime $date_end + * + * @return string + * @since 4.4.2 + * @version 1.0.0 */ - public function get_timestamp(): int { - return strtotime( $this->raw_date ); + public static function format_human_time_diff( DateTime $date_start, DateTime $date_end ): string { + $diff = $date_end->diff( $date_start ); + $week = floor( $diff->d / 7 ); + + $i18n_year = self::get_string_plural_duration( $diff->y, 'year' ); + $i18n_month = self::get_string_plural_duration( $diff->m, 'month' ); + $i18n_week = self::get_string_plural_duration( $week, 'week' ); + $i18n_day = self::get_string_plural_duration( $diff->d, 'day' ); + $i18n_hour = self::get_string_plural_duration( $diff->h, 'hour' ); + $i18n_minute = self::get_string_plural_duration( $diff->i, 'minute' ); + $i18n_second = self::get_string_plural_duration( $diff->s, 'second' ); + + $format_date = ''; + $string = array( + 'y' => '%y years', + 'm' => '%m months', + 'w' => '', // object don't have week, only add to custom week format + 'd' => '%d days, %h hours', + 'h' => '%h hours, %i minutes', + 'i' => '%i minutes, %s seconds', + 's' => $i18n_second, + ); + + foreach ( $string as $k => $v ) { + if ( isset( $diff->{$k} ) && $diff->{$k} > 0 ) { + switch ( $k ) { + case 'y': + $format_date = sprintf( + '%1$s%2$s', + $i18n_year, + $diff->m > 0 ? ', ' . $i18n_month : '' + ); + break; + case 'm': + $format_date = sprintf( + '%1$s%2$s', + $i18n_month, + $diff->d > 0 ? ', ' . $i18n_day : '' + ); + break; + case 'd': + $format_date = sprintf( + '%1$s%2$s', + $i18n_day, + $diff->h > 0 ? ', ' . $i18n_hour : '' + ); + break; + case 'h': + $format_date = sprintf( + '%1$s%2$s', + $i18n_hour, + $diff->i > 0 ? ', ' . $i18n_minute : '' + ); + break; + case 'i': + $format_date = sprintf( + '%1$s%2$s', + $i18n_minute, + $diff->s > 0 ? ', ' . $i18n_second : '' + ); + break; + default: + $format_date = $v; + break; + } + break; + } elseif ( 'w' === $k && $week > 0 ) { + $day_remain = $diff->d - $week * 7; + $format_date = sprintf( + '%1$s%2$s', + $i18n_week, + $day_remain > 0 ? ', ' . self::get_string_plural_duration( $day_remain, 'day' ) : '' + ); + break; + } + } + + return apply_filters( + 'learn-press/datetime/format_human_time_diff', + $format_date, + $diff, + $date_start, + $date_end + ); + } + + /** + * Get string plural duration. + * Clone from LP_Datetime::get_string_plural_duration since 4.2.3.5 + * + * @param int $duration_number + * @param string $duration_type + * + * @return string + * @version 1.0.0 + * @since 4.4.2 + */ + public static function get_string_plural_duration( int $duration_number, string $duration_type = '' ): string { + switch ( strtolower( $duration_type ) ) { + case 'second': + $duration_str = sprintf( + _n( '%s Second', '%s Seconds', $duration_number, 'learnpress' ), + $duration_number + ); + break; + case 'minute': + $duration_str = sprintf( + _n( '%s Minute', '%s Minutes', $duration_number, 'learnpress' ), + $duration_number + ); + break; + case 'hour': + $duration_str = sprintf( + _n( '%s Hour', '%s Hours', $duration_number, 'learnpress' ), + $duration_number + ); + break; + case 'day': + $duration_str = sprintf( + _n( '%s Day', '%s Days', $duration_number, 'learnpress' ), + $duration_number + ); + break; + case 'week': + $duration_str = sprintf( + _n( '%s Week', '%s Weeks', $duration_number, 'learnpress' ), + $duration_number + ); + break; + case 'month': + $duration_str = sprintf( + _n( '%s Month', '%s Months', $duration_number, 'learnpress' ), + $duration_number + ); + break; + case 'year': + $duration_str = sprintf( + _n( '%s Year', '%s Years', $duration_number, 'learnpress' ), + $duration_number + ); + break; + default: + $duration_str = $duration_number . ' ' . $duration_type; + } + + return apply_filters( 'learn-press/i18n/plural_duration', $duration_str, $duration_number, $duration_type ); } } diff --git a/inc/custom-post-types/order.php b/inc/custom-post-types/order.php index 46d6f3799d..594c6d592b 100644 --- a/inc/custom-post-types/order.php +++ b/inc/custom-post-types/order.php @@ -639,14 +639,21 @@ public function columns_content( $column, $post_id = 0 ) { $time = strtotime( $orderPostModel->post_date_gmt ); $time_diff = time() - $time; - $lpDateTime = new LP_Datetime( $orderPostModel->post_date_gmt ); - $time_local = $lpDateTime->format( LP_Datetime::I18N_FORMAT_HAS_TIME ); - $time_local_format_mysql = ( new LP_Datetime( $time_local ) )->format( LP_Datetime::$format ); + $lpDateTimeGMT = new LPDateTime( $orderPostModel->post_date_gmt ); + $time_local_format_mysql = $lpDateTimeGMT->format( LPDateTime::FORMAT_MYSQL, 'gmt_to_local' ); if ( $time_diff > 0 && $time_diff < DAY_IN_SECONDS ) { - $time_display = sprintf( __( '%s ago', 'learnpress' ), human_time_diff( $time ) ); + $time_display = $lpDateTimeGMT->format( + LPDateTime::FORMAT_HUMAN, + 'gmt_to_local', + true + ); } else { - $time_display = $lpDateTime->format( LP_Datetime::I18N_FORMAT_HAS_TIME ); + $time_display = $lpDateTimeGMT->format( + LPDateTime::FORMAT_I18N_DATE_TIME, + 'gmt_to_local', + true + ); } echo sprintf( @@ -654,9 +661,6 @@ public function columns_content( $column, $post_id = 0 ) { esc_attr( $time_local_format_mysql ), esc_html( $time_display ) ); - - $m = new LPDateTime( '2026-07-03 13:00:00' ); - echo '
' . $m->format( LPDateTime::FORMAT_I18N_DATE_TIME_TIMEZONE, true ) . '
'; break; case 'order_items': do_action( 'learn-press/admin/order-items/layout', $lp_order );