File: //var/www/biblioteka/wp-content/plugins/qtranslate-xt-3.15.2/src/date_time.php
<?php
/**
* Locale-formatted strftime using \IntlDateFormatter (PHP 8.1 compatible)
* This provides a cross-platform alternative to strftime() for when it will be removed from PHP.
* Note that output can be slightly different between libc sprintf and this function as it is using ICU.
* Non-standard strftime: '%q' is a qTranslate format to mimic date 'S'.
*
* Usage:
* echo strftime('%A %e %B %Y %X', new \DateTime('2021-09-28 00:00:00'), 'fr_FR');
*
* Original use:
* \setlocale('fr_FR.UTF-8', LC_TIME);
* echo \strftime('%A %e %B %Y %X', strtotime('2021-09-28 00:00:00'));
*
* @param string $format Date format
* @param integer|string|DateTime $timestamp Timestamp
*
* @return string
* @todo Maybe deprecate. Avoid using this function, meant to transition from legacy strftime formats.
* @see https://gist.github.com/bohwaz/42fc223031e2b2dd2585aab159a20f30 (for the original code).
*/
function qxtranxf_intl_strftime( string $format, $timestamp = null, ?string $locale = null ): string {
if ( null === $timestamp ) {
$timestamp = new \DateTime;
} elseif ( is_numeric( $timestamp ) ) {
$timestamp = date_create( '@' . $timestamp );
if ( $timestamp ) {
$timestamp->setTimezone( new \DateTimezone( date_default_timezone_get() ) );
}
} elseif ( is_string( $timestamp ) ) {
$timestamp = date_create( $timestamp );
}
if ( ! ( $timestamp instanceof \DateTimeInterface ) ) {
throw new \InvalidArgumentException( '$timestamp argument is neither a valid UNIX timestamp, a valid date-time string or a DateTime object.' );
}
$locale = substr( (string) $locale, 0, 5 );
// \DateTimeInterface, string
$intl_formatter = function ( DateTimeInterface $timestamp, string $format ) use ( $locale ) {
$intl_formats = [
'%a' => 'EEE', // An abbreviated textual representation of the day Sun through Sat
'%A' => 'EEEE', // A full textual representation of the day Sunday through Saturday
'%b' => 'MMM', // Abbreviated month name, based on the locale Jan through Dec
'%B' => 'MMMM', // Full month name, based on the locale January through December
'%h' => 'MMM', // Abbreviated month name, based on the locale (an alias of %b) Jan through Dec
];
$tz = $timestamp->getTimezone();
$date_type = \IntlDateFormatter::FULL;
$time_type = \IntlDateFormatter::FULL;
$pattern = '';
// %c = Preferred date and time stamp based on locale
// Example: Tue Feb 5 00:45:10 2009 for February 5, 2009 at 12:45:10 AM
if ( $format == '%c' ) {
$date_type = \IntlDateFormatter::LONG;
$time_type = \IntlDateFormatter::SHORT;
}
// %x = Preferred date representation based on locale, without the time
// Example: 02/05/09 for February 5, 2009
elseif ( $format == '%x' ) {
$date_type = \IntlDateFormatter::SHORT;
$time_type = \IntlDateFormatter::NONE;
} // Localized time format
elseif ( $format == '%X' ) {
$date_type = \IntlDateFormatter::NONE;
$time_type = \IntlDateFormatter::MEDIUM;
} else {
$pattern = $intl_formats[ $format ];
}
return ( new \IntlDateFormatter( $locale, $date_type, $time_type, $tz, null, $pattern ) )->format( $timestamp );
};
// Same order as https://www.php.net/manual/en/function.strftime.php
$translation_table = [
// Day
'%a' => $intl_formatter,
'%A' => $intl_formatter,
'%d' => 'd',
'%e' => function ( $timestamp ) {
return sprintf( '% 2u', $timestamp->format( 'j' ) );
},
'%j' => function ( $timestamp ) {
// Day number in year, 001 to 366
return sprintf( '%03d', $timestamp->format( 'z' ) + 1 );
},
'%u' => 'N',
'%w' => 'w',
// Week
'%U' => function ( $timestamp ) {
// Number of weeks between date and first Sunday of year
$day = new \DateTime( sprintf( '%d-01 Sunday', $timestamp->format( 'Y' ) ) );
return sprintf( '%02u', 1 + ( $timestamp->format( 'z' ) - $day->format( 'z' ) ) / 7 );
},
'%V' => 'W',
'%W' => function ( $timestamp ) {
// Number of weeks between date and first Monday of year
$day = new \DateTime( sprintf( '%d-01 Monday', $timestamp->format( 'Y' ) ) );
return sprintf( '%02u', 1 + ( $timestamp->format( 'z' ) - $day->format( 'z' ) ) / 7 );
},
// Month
'%b' => $intl_formatter,
'%B' => $intl_formatter,
'%h' => $intl_formatter,
'%m' => 'm',
// Year
'%C' => function ( $timestamp ) {
// Century (-1): 19 for 20th century
return floor( $timestamp->format( 'Y' ) / 100 );
},
'%g' => function ( $timestamp ) {
return substr( $timestamp->format( 'o' ), -2 );
},
'%G' => 'o',
'%y' => 'y',
'%Y' => 'Y',
// Time
'%H' => 'H',
'%k' => function ( $timestamp ) {
return sprintf( '% 2u', $timestamp->format( 'G' ) );
},
'%I' => 'h',
'%l' => function ( $timestamp ) {
return sprintf( '% 2u', $timestamp->format( 'g' ) );
},
'%M' => 'i',
'%p' => 'A', // AM PM (this is reversed on purpose!)
'%P' => 'a', // am pm
'%r' => 'h:i:s A', // %I:%M:%S %p
'%R' => 'H:i', // %H:%M
'%S' => 's',
'%T' => 'H:i:s', // %H:%M:%S
'%X' => $intl_formatter, // Preferred time representation based on locale, without the date
// Timezone
'%z' => 'O',
'%Z' => 'T',
// Time and Date Stamps
'%c' => $intl_formatter,
'%D' => 'm/d/Y',
'%F' => 'Y-m-d',
'%s' => 'U',
'%x' => $intl_formatter,
// QTranslate: non-standard strftime
'%E' => 'j', // Day number no zero
'%q' => 'S', // Day english ordinal
'%f' => 'w', // Week number
'%v' => 'T', // Timezone abbreviation, if known; otherwise the GMT offset.
'%i' => 'n', // Numeric representation of a month, without leading zeros
'%J' => 't', // Number of days in the given month
'%K' => 'B', // Swatch internet time 000-999
'%L' => 'G', // 24-hour format of an hour without leading zeros ---> %L should be %k!
'%N' => 'u', // Microseconds
'%Q' => 'e', // Timezone identifier
'%o' => 'I', // 1 if Daylight Saving Time, 0 otherwise.
'%O' => 'O', // Difference to Greenwich time (GMT) without colon between hours and minutes
'%1' => 'Z', // Timezone offset in seconds
'%2' => 'c', // ISO 8601 date
'%3' => 'r', // RFC 2822/» RFC 5322 formatted date
'%4' => 'U', // Seconds since the Unix Epoch
];
$out = preg_replace_callback( '/(?<!%)(%[a-zA-Z])/', function ( $match ) use ( $translation_table, $timestamp ) {
if ( $match[1] == '%n' ) {
return "\n";
} elseif ( $match[1] == '%t' ) {
return "\t";
}
if ( ! isset( $translation_table[ $match[1] ] ) ) {
throw new \InvalidArgumentException( sprintf( 'Format "%s" is unknown in time format', $match[1] ) );
}
$replace = $translation_table[ $match[1] ];
if ( is_string( $replace ) ) {
return $timestamp->format( $replace );
} else {
return $replace( $timestamp, $match[1] );
}
}, $format );
return str_replace( '%%', '%', $out );
}
/**
* Converter of a format given in DateTime format, transformed to the extended "QTX-strftime" format.
*
* @param string $format in DateTime format. Format characters can be quoted with backslashes.
*
* @return string
* @todo Maybe deprecate. Don't use strftime formats anymore, since strftime is deprecated from PHP8.1.
* @see https://www.php.net/manual/en/function.strftime.php
* @see https://www.php.net/manual/en/datetime.format.php
*/
function qtranxf_convert_date_format_to_strftime_format( string $format ): string {
$mappings = array(
// day
'd' => '%d',
'D' => '%a',
'l' => '%A',
'N' => '%u',
// week
'W' => '%V',
// month
'F' => '%B',
'm' => '%m',
'M' => '%b',
// year
'o' => '%G',
'Y' => '%Y',
'y' => '%y',
// time
'a' => '%P',
'A' => '%p',
'g' => '%l',
'h' => '%I',
'H' => '%H',
'i' => '%M',
's' => '%S',
// QTranslate: override strftime, not consistent with date formats :-/
'z' => '%F', // z: The day of the year (starting from 0) -- %F: Same as "%Y-%m-%d
'P' => '%s', // P: Difference to Greenwich time (GMT) with colon between hours and minutes -- %s: unix timestamp
'L' => '%k', // L: leap year -- %k: Hour in 24-hour format, single digit
// QTranslate: non-standard strftime to mimic some date formats
'j' => '%E', // Day number no zero
'S' => '%q', // Day english ordinal
'w' => '%f', // Week number
'T' => '%v', // Timezone abbreviation, if known; otherwise the GMT offset.
'n' => '%i', // Numeric representation of a month, without leading zeros
't' => '%J', // Number of days in the given month
'B' => '%K', // Swatch internet time 000-999
'G' => '%L', // 24-hour format of an hour without leading zeros --> %L should be %k!
'u' => '%N', // Microseconds
'e' => '%Q', // Timezone identifier
'I' => '%o', // 1 if Daylight Saving Time, 0 otherwise.
'O' => '%O', // Difference to Greenwich time (GMT) without colon between hours and minutes
'Z' => '%1', // Timezone offset in seconds
'c' => '%2', // ISO 8601 date
'r' => '%3', // RFC 2822/» RFC 5322 formatted date
'U' => '%4' // Seconds since the Unix Epoch
);
$date_parameters = array();
$strftime_parameters = array();
$date_parameters[] = '#%#';
$strftime_parameters[] = '%';
foreach ( $mappings as $df => $sf ) {
// Format characters can be quoted with backslashes.
$date_parameters[] = '#(([^%\\\\])' . $df . '|^' . $df . ')#';
$strftime_parameters[] = '${2}' . $sf;
}
// convert everything
$format = preg_replace( $date_parameters, $strftime_parameters, $format );
// Remove single backslashes and convert double to single.
return stripslashes( $format );
}
/**
* Converter of a format/default pair to "QTX-strftime" format, applying 'use_strftime' configuration.
*
* @param string $format ATTENTION - always given in date PHP format.
* @param string $default_format language format following the 'use_strftime' configuration.
*
* @return string format in strftime
* @todo Maybe deprecate. Don't use strftime formats anymore, since strftime is deprecated from PHP8.1.
*/
function qtranxf_convert_to_strftime_format_using_config( string $format, string $default_format ): string {
global $q_config;
// If one of special language-neutral formats is requested, don't override it.
switch ( $format ) {
case 'Z':
case 'c':
case 'r':
case 'U':
return qtranxf_convert_date_format_to_strftime_format( $format );
}
// Attention - this part is quite tricky.
// The user format is always given in date format, but not the language format which depends on use_strftime settings.
// The language format may contain escape backslash characters that must be unquoted in any case.
switch ( $q_config['use_strftime'] ) {
case QTX_DATE:
// Convert both.
return qtranxf_convert_date_format_to_strftime_format( ! empty( $format ) ? $format : $default_format );
case QTX_DATE_OVERRIDE:
return qtranxf_convert_date_format_to_strftime_format( $default_format );
case QTX_STRFTIME:
return ( ! empty( $format ) ? qtranxf_convert_date_format_to_strftime_format( $format ) : stripslashes( $default_format ) );
case QTX_STRFTIME_OVERRIDE:
return stripslashes( $default_format );
case QTX_DATE_WP:
default:
return '';
}
}
/**
* Return the date or time format set for the current language config or default language.
*
* @param string $config_key
*
* @return string
*/
function qtranxf_get_language_date_or_time_format( string $config_key ): string {
assert( $config_key == 'date_format' || $config_key == 'time_format' );
global $q_config;
if ( isset( $q_config[ $config_key ][ $q_config['language'] ] ) ) {
return $q_config[ $config_key ][ $q_config['language'] ];
} elseif ( isset( $q_config[ $config_key ][ $q_config['default_language'] ] ) ) {
return $q_config[ $config_key ][ $q_config['default_language'] ];
} else {
return '';
}
}
/**
* [Legacy] Generalized formatting of a date, applying qTranslate 'use_strftime' config.
*
* @param string $format
* @param string $mysql_time date string in MySQL format
* @param string $default_value default date value.
* @param string $before Deprecated. Not used, will be removed in a future version.
* @param string $after Deprecated. Not used, will be removed in a future version.
*
* @return string|int date/time if $format and $mysql_time are valid, default value otherwise.
*/
function qtranxf_format_date( string $format, string $mysql_time, string $default_value, string $before = '', string $after = '' ) {
if ( ! empty( $before ) || ! empty( $after ) ) {
_deprecated_argument( __FUNCTION__, '3.13.0' );
}
$timestamp = mysql2date( 'U', $mysql_time );
if ( $timestamp === false ) {
return $default_value;
}
if ( $format == 'U' ) {
return $timestamp;
}
$language_format = qtranxf_get_language_date_or_time_format( 'date_format' );
// TODO: abandon strftime format in qTranslate.
$date_format = qtranxf_convert_to_strftime_format_using_config( $format, $language_format );
return ( ! empty( $date_format ) ? qxtranxf_intl_strftime( $date_format, $timestamp, get_locale() ) : $default_value );
}
/**
* [Legacy] Generalized formatting of a date, applying qTranslate 'use_strftime' config.
*
* @param string $format
* @param string $mysql_time time string in MySQL format
* @param string $default_value default time value.
* @param string $before Deprecated. Not used, will be removed in a future version.
* @param string $after Deprecated. Not used, will be removed in a future version.
*
* @return string|int date/time if $format and $mysql_time are valid, default value otherwise.
*/
function qtranxf_format_time( string $format, string $mysql_time, string $default_value, string $before = '', string $after = '' ) {
if ( ! empty( $before ) || ! empty( $after ) ) {
_deprecated_argument( __FUNCTION__, '3.13.0' );
}
$timestamp = mysql2date( 'U', $mysql_time );
if ( $timestamp === false ) {
return $default_value;
}
if ( $format == 'U' ) {
return $timestamp;
}
$language_format = qtranxf_get_language_date_or_time_format( 'time_format' );
// TODO: abandon strftime format in qTranslate.
$date_format = qtranxf_convert_to_strftime_format_using_config( $format, $language_format );
return ( ! empty( $date_format ) ? qxtranxf_intl_strftime( $date_format, $timestamp, get_locale() ) : $default_value );
}
/**
* Filter for `get_the_date`.
*/
function qtranxf_dateFromPostForCurrentLanguage( $old_date, string $format, WP_Post $post ) {
return qtranxf_format_date( $format, $post->post_date, $old_date );
}
/**
* Filter for `get_the_time`.
*/
function qtranxf_timeFromPostForCurrentLanguage( $old_date, string $format, WP_Post $post ) {
return qtranxf_format_time( $format, $post->post_date, $old_date );
}
/**
* Filter for `get_the_modified_date`.
*/
function qtranxf_dateModifiedFromPostForCurrentLanguage( $old_date, string $format, ?WP_Post $post ) {
return isset( $post ) ? qtranxf_format_date( $format, $post->post_modified, $old_date ) : $old_date;
}
/**
* Filter for `get_post_modified_time`.
*/
function qtranxf_timeModifiedFromPostForCurrentLanguage( $time, string $format, bool $gmt ) {
// No post given in the WordPress filter, there's nothing valuable we can do :(
// TODO make a feature request to WordPress to get the WP_Post object as for `get_the_modified_date`.
return $time;
}
/**
* Filter for `get_comment_date`.
*/
function qtranxf_dateFromCommentForCurrentLanguage( $old_date, string $format, WP_Comment $comment ) {
return qtranxf_format_date( $format, $comment->comment_date, $old_date );
}
/**
* Filter for `get_comment_time`.
*/
function qtranxf_timeFromCommentForCurrentLanguage( $old_date, string $format, bool $gmt, bool $translate, WP_Comment $comment ) {
if ( ! $translate ) {
return $old_date;
}
$comment_date = $gmt ? $comment->comment_date_gmt : $comment->comment_date;
return qtranxf_format_time( $format, $comment_date, $old_date );
}
/**
* Add date/time filters if the configuration allows it.
*
* @return void
*/
function qtranxf_add_date_time_filters(): void {
global $q_config;
if ( $q_config['use_strftime'] != QTX_DATE_WP && class_exists( 'IntlDateFormatter' ) ) {
add_filter( 'get_the_date', 'qtranxf_dateFromPostForCurrentLanguage', 0, 3 );
add_filter( 'get_the_time', 'qtranxf_timeFromPostForCurrentLanguage', 0, 3 );
add_filter( 'get_the_modified_date', 'qtranxf_dateModifiedFromPostForCurrentLanguage', 0, 3 );
add_filter( 'get_post_modified_time', 'qtranxf_timeModifiedFromPostForCurrentLanguage', 0, 3 );
add_filter( 'get_comment_date', 'qtranxf_dateFromCommentForCurrentLanguage', 0, 3 );
add_filter( 'get_comment_time', 'qtranxf_timeFromCommentForCurrentLanguage', 0, 5 );
}
}