require ABSPATH . WPINC . '/option.php';
* Convert given MySQL date string into a different format.
* `$format` should be a PHP date format string.
* 'U' and 'G' formats will return a sum of timestamp with timezone offset.
* `$date` is expected to be local time in MySQL format (`Y-m-d H:i:s`).
* Historically UTC time could be passed to the function to produce Unix timestamp.
* If `$translate` is true then the given date and format string will
* be passed to `wp_date()` for translation.
* @param string $format Format of the date to return.
* @param string $date Date string to convert.
* @param bool $translate Whether the return date should be translated. Default true.
* @return string|int|false Formatted date string or sum of Unix timestamp and timezone offset.
function mysql2date( $format, $date, $translate = true ) {
$datetime = date_create( $date, wp_timezone() );
if ( false === $datetime ) {
// Returns a sum of timestamp with timezone offset. Ideally should never be used.
if ( 'G' === $format || 'U' === $format ) {
return $datetime->getTimestamp() + $datetime->getOffset();
return wp_date( $format, $datetime->getTimestamp() );
return $datetime->format( $format );
* Retrieves the current time based on specified type.
* The 'mysql' type will return the time in the format for MySQL DATETIME field.
* The 'timestamp' type will return the current timestamp or a sum of timestamp
* and timezone offset, depending on `$gmt`.
* Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d').
* If $gmt is set to either '1' or 'true', then both types will use GMT time.
* if $gmt is false, the output is adjusted with the GMT offset in the WordPress option.
* @param string $type Type of time to retrieve. Accepts 'mysql', 'timestamp',
* or PHP date format string (e.g. 'Y-m-d').
* @param int|bool $gmt Optional. Whether to use GMT timezone. Default false.
* @return int|string Integer if $type is 'timestamp', string otherwise.
function current_time( $type, $gmt = 0 ) {
// Don't use non-GMT timestamp, unless you know the difference and really need to.
if ( 'timestamp' === $type || 'U' === $type ) {
return $gmt ? time() : time() + (int) ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
if ( 'mysql' === $type ) {
$timezone = $gmt ? new DateTimeZone( 'UTC' ) : wp_timezone();
$datetime = new DateTime( 'now', $timezone );
return $datetime->format( $type );
* Retrieves the current time as an object with the timezone from settings.
* @return DateTimeImmutable Date and time object.
function current_datetime() {
return new DateTimeImmutable( 'now', wp_timezone() );
* Retrieves the timezone from site settings as a string.
* Uses the `timezone_string` option to get a proper timezone if available,
* otherwise falls back to an offset.
* @return string PHP timezone string or a ±HH:MM offset.
function wp_timezone_string() {
$timezone_string = get_option( 'timezone_string' );
if ( $timezone_string ) {
$offset = (float) get_option( 'gmt_offset' );
$minutes = ( $offset - $hours );
$sign = ( $offset < 0 ) ? '-' : '+';
$abs_hour = abs( $hours );
$abs_mins = abs( $minutes * 60 );
$tz_offset = sprintf( '%s%02d:%02d', $sign, $abs_hour, $abs_mins );
* Retrieves the timezone from site settings as a `DateTimeZone` object.
* Timezone can be based on a PHP timezone string or a ±HH:MM offset.
* @return DateTimeZone Timezone object.
return new DateTimeZone( wp_timezone_string() );
* Retrieves the date in localized format, based on a sum of Unix timestamp and
* timezone offset in seconds.
* If the locale specifies the locale month and weekday, then the locale will
* take over the format for the date. If it isn't, then the date format string
* Note that due to the way WP typically generates a sum of timestamp and offset
* with `strtotime()`, it implies offset added at a _current_ time, not at the time
* the timestamp represents. Storing such timestamps or calculating them differently
* will lead to invalid output.
* @since 5.3.0 Converted into a wrapper for wp_date().
* @global WP_Locale $wp_locale WordPress date and time locale object.
* @param string $format Format to display the date.
* @param int|bool $timestamp_with_offset Optional. A sum of Unix timestamp and timezone offset
* in seconds. Default false.
* @param bool $gmt Optional. Whether to use GMT timezone. Only applies
* if timestamp is not provided. Default false.
* @return string The date, translated if locale specifies it.
function date_i18n( $format, $timestamp_with_offset = false, $gmt = false ) {
$timestamp = $timestamp_with_offset;
// If timestamp is omitted it should be current time (summed with offset, unless `$gmt` is true).
if ( ! is_numeric( $timestamp ) ) {
$timestamp = current_time( 'timestamp', $gmt );
* This is a legacy implementation quirk that the returned timestamp is also with offset.
* Ideally this function should never be used to produce a timestamp.
} elseif ( $gmt && false === $timestamp_with_offset ) { // Current time in UTC.
$date = wp_date( $format, null, new DateTimeZone( 'UTC' ) );
} elseif ( false === $timestamp_with_offset ) { // Current time in site's timezone.
$date = wp_date( $format );
* Timestamp with offset is typically produced by a UTC `strtotime()` call on an input without timezone.
* This is the best attempt to reverse that operation into a local time to use.
$local_time = gmdate( 'Y-m-d H:i:s', $timestamp );
$timezone = wp_timezone();
$datetime = date_create( $local_time, $timezone );
$date = wp_date( $format, $datetime->getTimestamp(), $timezone );
* Filters the date formatted based on the locale.
* @param string $date Formatted date string.
* @param string $format Format to display the date.
* @param int $timestamp A sum of Unix timestamp and timezone offset in seconds.
* Might be without offset if input omitted timestamp but requested GMT.
* @param bool $gmt Whether to use GMT timezone. Only applies if timestamp was not provided.
$date = apply_filters( 'date_i18n', $date, $format, $timestamp, $gmt );
* Retrieves the date, in localized format.
* This is a newer function, intended to replace `date_i18n()` without legacy quirks in it.
* Note that, unlike `date_i18n()`, this function accepts a true Unix timestamp, not summed
* @param string $format PHP date format.
* @param int $timestamp Optional. Unix timestamp. Defaults to current time.
* @param DateTimeZone $timezone Optional. Timezone to output result in. Defaults to timezone
* @return string|false The date, translated if locale specifies it. False on invalid timestamp input.
function wp_date( $format, $timestamp = null, $timezone = null ) {
if ( null === $timestamp ) {
} elseif ( ! is_numeric( $timestamp ) ) {
$timezone = wp_timezone();
$datetime = date_create( '@' . $timestamp );
$datetime->setTimezone( $timezone );
if ( empty( $wp_locale->month ) || empty( $wp_locale->weekday ) ) {
$date = $datetime->format( $format );
// We need to unpack shorthand `r` format because it has parts that might be localized.
$format = preg_replace( '/(?<!\\\\)r/', DATE_RFC2822, $format );
$format_length = strlen( $format );
$month = $wp_locale->get_month( $datetime->format( 'm' ) );
$weekday = $wp_locale->get_weekday( $datetime->format( 'w' ) );
for ( $i = 0; $i < $format_length; $i ++ ) {
switch ( $format[ $i ] ) {
$new_format .= addcslashes( $wp_locale->get_weekday_abbrev( $weekday ), '\\A..Za..z' );
$new_format .= addcslashes( $month, '\\A..Za..z' );
$new_format .= addcslashes( $weekday, '\\A..Za..z' );
$new_format .= addcslashes( $wp_locale->get_month_abbrev( $month ), '\\A..Za..z' );
$new_format .= addcslashes( $wp_locale->get_meridiem( $datetime->format( 'a' ) ), '\\A..Za..z' );
$new_format .= addcslashes( $wp_locale->get_meridiem( $datetime->format( 'A' ) ), '\\A..Za..z' );
$new_format .= $format[ $i ];
// If character follows a slash, we add it without translating.
if ( $i < $format_length ) {
$new_format .= $format[ ++$i ];
$new_format .= $format[ $i ];
$date = $datetime->format( $new_format );
$date = wp_maybe_decline_date( $date, $format );
* Filters the date formatted based on the locale.
* @param string $date Formatted date string.
* @param string $format Format to display the date.
* @param int $timestamp Unix timestamp.
* @param DateTimeZone $timezone Timezone.
$date = apply_filters( 'wp_date', $date, $format, $timestamp, $timezone );
* Determines if the date should be declined.
* If the locale specifies that month names require a genitive case in certain
* formats (like 'j F Y'), the month name will be replaced with a correct form.
* @since 5.4.0 The `$format` parameter was added.
* @global WP_Locale $wp_locale WordPress date and time locale object.
* @param string $date Formatted date string.
* @param string $format Optional. Date format to check. Default empty string.
* @return string The date, declined if locale specifies it.
function wp_maybe_decline_date( $date, $format = '' ) {
// i18n functions are not available in SHORTINIT mode.
if ( ! function_exists( '_x' ) ) {
* translators: If months in your language require a genitive case,
* translate this to 'on'. Do not translate into your own language.
if ( 'on' === _x( 'off', 'decline months names: on or off' ) ) {
$months = $wp_locale->month;
$months_genitive = $wp_locale->month_genitive;
* Match a format like 'j F Y' or 'j. F' (day of the month, followed by month name)
$decline = preg_match( '#[dj]\.? F#', $format );
// If the format is not passed, try to guess it from the date string.
$decline = preg_match( '#\b\d{1,2}\.? [^\d ]+\b#u', $date );
foreach ( $months as $key => $month ) {
$months[ $key ] = '# ' . preg_quote( $month, '#' ) . '\b#u';
foreach ( $months_genitive as $key => $month ) {
$months_genitive[ $key ] = ' ' . $month;
$date = preg_replace( $months, $months_genitive, $date );
* Match a format like 'F jS' or 'F j' (month name, followed by day with an optional ordinal suffix)
* and change it to declined 'j F'.
$decline = preg_match( '#F [dj]#', $format );
// If the format is not passed, try to guess it from the date string.
$decline = preg_match( '#\b[^\d ]+ \d{1,2}(st|nd|rd|th)?\b#u', trim( $date ) );
foreach ( $months as $key => $month ) {
$months[ $key ] = '#\b' . preg_quote( $month, '#' ) . ' (\d{1,2})(st|nd|rd|th)?([-–]\d{1,2})?(st|nd|rd|th)?\b#u';
foreach ( $months_genitive as $key => $month ) {
$months_genitive[ $key ] = '$1$3 ' . $month;
$date = preg_replace( $months, $months_genitive, $date );
// Used for locale-specific rules.
if ( 'ca' === $locale ) {
// " de abril| de agost| de octubre..." -> " d'abril| d'agost| d'octubre..."
$date = preg_replace( '# de ([ao])#i', " d'\\1", $date );
* Convert float number to format based on the locale.
* @global WP_Locale $wp_locale WordPress date and time locale object.
* @param float $number The number to convert based on locale.
* @param int $decimals Optional. Precision of the number of decimal places. Default 0.
* @return string Converted number in string format.
function number_format_i18n( $number, $decimals = 0 ) {
if ( isset( $wp_locale ) ) {
$formatted = number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
$formatted = number_format( $number, absint( $decimals ) );
* Filters the number formatted based on the locale.
* @since 4.9.0 The `$number` and `$decimals` parameters were added.
* @param string $formatted Converted number in string format.
* @param float $number The number to convert based on locale.
* @param int $decimals Precision of the number of decimal places.
return apply_filters( 'number_format_i18n', $formatted, $number, $decimals );
* Convert number of bytes largest unit bytes will fit into.
* It is easier to read 1 KB than 1024 bytes and 1 MB than 1048576 bytes. Converts
* number of bytes to human readable number by taking the number of that unit
* that the bytes will go into it. Supports TB value.
* Please note that integers in PHP are limited to 32 bits, unless they are on
* 64 bit architecture, then they have 64 bit size. If you need to place the
* larger size then what PHP integer type will hold, then use a string. It will
* be converted to a double, which should always have 64 bit length.
* Technically the correct unit names for powers of 1024 are KiB, MiB etc.
* @param int|string $bytes Number of bytes. Note max integer size for integers.
* @param int $decimals Optional. Precision of number of decimal places. Default 0.
* @return string|false Number string on success, false on failure.
function size_format( $bytes, $decimals = 0 ) {
/* translators: Unit symbol for terabyte. */
_x( 'TB', 'unit symbol' ) => TB_IN_BYTES,
/* translators: Unit symbol for gigabyte. */
_x( 'GB', 'unit symbol' ) => GB_IN_BYTES,
/* translators: Unit symbol for megabyte. */
_x( 'MB', 'unit symbol' ) => MB_IN_BYTES,
/* translators: Unit symbol for kilobyte. */
_x( 'KB', 'unit symbol' ) => KB_IN_BYTES,
/* translators: Unit symbol for byte. */
_x( 'B', 'unit symbol' ) => 1,
/* translators: Unit symbol for byte. */
return number_format_i18n( 0, $decimals ) . ' ' . _x( 'B', 'unit symbol' );
foreach ( $quant as $unit => $mag ) {
if ( (float) $bytes >= $mag ) {
return number_format_i18n( $bytes / $mag, $decimals ) . ' ' . $unit;
* Convert a duration to human readable format.
* @param string $duration Duration will be in string format (HH:ii:ss) OR (ii:ss),
* with a possible prepended negative sign (-).
* @return string|false A human readable duration string, false on failure.
function human_readable_duration( $duration = '' ) {
if ( ( empty( $duration ) || ! is_string( $duration ) ) ) {
$duration = trim( $duration );
// Remove prepended negative sign.
if ( '-' === substr( $duration, 0, 1 ) ) {
$duration = substr( $duration, 1 );
// Extract duration parts.
$duration_parts = array_reverse( explode( ':', $duration ) );