Changeset 45882
- Timestamp:
- 08/23/2019 12:56:21 AM (5 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/functions.php
r45877 r45882 129 129 * take over the format for the date. If it isn't, then the date format string 130 130 * will be used instead. 131 * 132 * Note that due to the way WP typically generates a sum of timestamp and offset 133 * with `strtotime()`, it implies offset added at a _current_ time, not at the time 134 * the timestamp represents. Storing such timestamps or calculating them differently 135 * will lead to invalid output. 131 136 * 132 137 * @since 0.71 … … 144 149 function date_i18n( $dateformatstring, $timestamp_with_offset = false, $gmt = false ) { 145 150 global $wp_locale; 151 146 152 $i = $timestamp_with_offset; 147 153 … … 155 161 */ 156 162 $req_format = $dateformatstring; 157 158 $dateformatstring = preg_replace( '/(?<!\\\\)c/', DATE_W3C, $dateformatstring ); 163 $new_format = ''; 164 165 // We need to unpack shorthand `r` format because it has parts that might be localized. 159 166 $dateformatstring = preg_replace( '/(?<!\\\\)r/', DATE_RFC2822, $dateformatstring ); 160 167 161 if ( ( ! empty( $wp_locale->month ) ) && ( ! empty( $wp_locale->weekday ) ) ) { 162 $datemonth = $wp_locale->get_month( gmdate( 'm', $i ) ); 163 $datemonth_abbrev = $wp_locale->get_month_abbrev( $datemonth ); 164 $dateweekday = $wp_locale->get_weekday( gmdate( 'w', $i ) ); 165 $dateweekday_abbrev = $wp_locale->get_weekday_abbrev( $dateweekday ); 166 $datemeridiem = $wp_locale->get_meridiem( gmdate( 'a', $i ) ); 167 $datemeridiem_capital = $wp_locale->get_meridiem( gmdate( 'A', $i ) ); 168 $dateformatstring = ' ' . $dateformatstring; 169 $dateformatstring = preg_replace( '/([^\\\])D/', "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring ); 170 $dateformatstring = preg_replace( '/([^\\\])F/', "\\1" . backslashit( $datemonth ), $dateformatstring ); 171 $dateformatstring = preg_replace( '/([^\\\])l/', "\\1" . backslashit( $dateweekday ), $dateformatstring ); 172 $dateformatstring = preg_replace( '/([^\\\])M/', "\\1" . backslashit( $datemonth_abbrev ), $dateformatstring ); 173 $dateformatstring = preg_replace( '/([^\\\])a/', "\\1" . backslashit( $datemeridiem ), $dateformatstring ); 174 $dateformatstring = preg_replace( '/([^\\\])A/', "\\1" . backslashit( $datemeridiem_capital ), $dateformatstring ); 175 176 $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) - 1 ); 177 } 178 $timezone_formats = array( 'P', 'I', 'O', 'T', 'Z', 'e' ); 179 $timezone_formats_re = implode( '|', $timezone_formats ); 180 if ( preg_match( "/$timezone_formats_re/", $dateformatstring ) ) { 181 $timezone_string = get_option( 'timezone_string' ); 182 if ( false === $timestamp_with_offset && $gmt ) { 183 $timezone_string = 'UTC'; 184 } 185 if ( $timezone_string ) { 186 $timezone_object = timezone_open( $timezone_string ); 187 $date_object = date_create( null, $timezone_object ); 188 foreach ( $timezone_formats as $timezone_format ) { 189 if ( false !== strpos( $dateformatstring, $timezone_format ) ) { 190 $formatted = date_format( $date_object, $timezone_format ); 191 $dateformatstring = ' ' . $dateformatstring; 192 $dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring ); 193 $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) - 1 ); 194 } 168 /* 169 * Timestamp with offset is typically produced by a UTC `strtotime()` call on an input without timezone. 170 * This is the best attempt to reverse that operation into a local time to use. 171 */ 172 $local_time = gmdate( 'Y-m-d H:i:s', $i ); 173 $gmt_mode = $gmt && ( false === $timestamp_with_offset ); 174 $timezone = $gmt_mode ? new DateTimeZone( 'UTC' ) : wp_timezone(); 175 $datetime = date_create( $local_time, $timezone ); 176 177 /* 178 * This is a legacy implementation quirk that the returned timestamp is also with offset. 179 * Ideally this function should never be used to produce a timestamp. 180 */ 181 $timestamp_mode = ( 'U' === $dateformatstring ); 182 183 if ( $timestamp_mode ) { 184 $new_format = $i; 185 } 186 187 if ( ! $timestamp_mode && ! empty( $wp_locale->month ) && ! empty( $wp_locale->weekday ) ) { 188 $month = $wp_locale->get_month( $datetime->format( 'm' ) ); 189 $weekday = $wp_locale->get_weekday( $datetime->format( 'w' ) ); 190 191 $format_length = strlen( $dateformatstring ); 192 193 for ( $i = 0; $i < $format_length; $i ++ ) { 194 switch ( $dateformatstring[ $i ] ) { 195 case 'D': 196 $new_format .= backslashit( $wp_locale->get_weekday_abbrev( $weekday ) ); 197 break; 198 case 'F': 199 $new_format .= backslashit( $month ); 200 break; 201 case 'l': 202 $new_format .= backslashit( $weekday ); 203 break; 204 case 'M': 205 $new_format .= backslashit( $wp_locale->get_month_abbrev( $month ) ); 206 break; 207 case 'a': 208 $new_format .= backslashit( $wp_locale->get_meridiem( $datetime->format( 'a' ) ) ); 209 break; 210 case 'A': 211 $new_format .= backslashit( $wp_locale->get_meridiem( $datetime->format( 'A' ) ) ); 212 break; 213 case '\\': 214 $new_format .= $dateformatstring[ $i ]; 215 216 // If character follows a slash, we add it without translating. 217 if ( $i < $format_length ) { 218 $new_format .= $dateformatstring[ ++$i ]; 219 } 220 break; 221 default: 222 $new_format .= $dateformatstring[ $i ]; 223 break; 195 224 } 196 } else { 197 $offset = get_option( 'gmt_offset' ); 198 foreach ( $timezone_formats as $timezone_format ) { 199 if ( 'I' === $timezone_format ) { 200 continue; 201 } 202 203 if ( false !== strpos( $dateformatstring, $timezone_format ) ) { 204 if ( 'Z' === $timezone_format ) { 205 $formatted = (string) ( $offset * HOUR_IN_SECONDS ); 206 } else { 207 $prefix = ''; 208 $hours = (int) $offset; 209 $separator = ''; 210 $minutes = abs( ( $offset - $hours ) * 60 ); 211 212 if ( 'T' === $timezone_format ) { 213 $prefix = 'GMT'; 214 } elseif ( 'e' === $timezone_format || 'P' === $timezone_format ) { 215 $separator = ':'; 216 } 217 218 $formatted = sprintf( '%s%+03d%s%02d', $prefix, $hours, $separator, $minutes ); 219 } 220 221 $dateformatstring = ' ' . $dateformatstring; 222 $dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring ); 223 $dateformatstring = substr( $dateformatstring, 1 ); 224 } 225 } 226 } 227 } 228 $j = gmdate( $dateformatstring, $i ); 225 } 226 } 227 228 $j = $datetime->format( $new_format ); 229 229 230 230 /** … … 240 240 */ 241 241 $j = apply_filters( 'date_i18n', $j, $req_format, $i, $gmt ); 242 242 243 return $j; 243 244 } … … 1554 1555 */ 1555 1556 echo apply_filters( 'robots_txt', $output, $public ); 1557 } 1558 1559 /** 1560 * Display the robots.txt file content. 1561 * 1562 * The echo content should be with usage of the permalinks or for creating the 1563 * robots.txt file. 1564 * 1565 * @since 5.3.0 1566 */ 1567 function do_favicon() { 1568 /** 1569 * Fires when serving the favicon.ico file. 1570 * 1571 * @since 5.3.0 1572 */ 1573 do_action( 'do_faviconico' ); 1574 1575 wp_safe_redirect( esc_url( get_site_icon_url( 32, admin_url( 'images/w-logo-blue.png' ) ) ) ); 1576 1577 } 1578 1579 /** 1580 * Don't load all of WordPress when handling a favicon.ico request. 1581 * 1582 * Instead, send the headers for a zero-length favicon and bail. 1583 * 1584 * @since 3.0.0 1585 */ 1586 function wp_favicon_request() { 1587 if ( '/favicon.ico' == $_SERVER['REQUEST_URI'] ) { 1588 header( 'Content-Type: image/vnd.microsoft.icon' ); 1589 exit; 1590 } 1556 1591 } 1557 1592 -
trunk/tests/phpunit/tests/date/dateI18n.php
r45424 r45882 16 16 public function test_date_should_be_in_gmt() { 17 17 $this->assertEquals( strtotime( gmdate( DATE_RFC3339 ) ), strtotime( date_i18n( DATE_RFC3339, false, true ) ), 'The dates should be equal', 2 ); 18 }19 20 public function test_custom_timestamp_ignores_gmt_setting() {21 $this->assertEquals( '2012-12-01 00:00:00', date_i18n( 'Y-m-d H:i:s', strtotime( '2012-12-01 00:00:00' ) ) );22 18 } 23 19 … … 86 82 87 83 /** 84 * @ticket 20973 85 * 88 86 * @dataProvider data_formats 89 * @ticket 2097390 87 */ 91 88 public function test_date_i18n_handles_shorthand_formats( $short, $full ) { … … 108 105 ); 109 106 } 107 108 /** 109 * @ticket 25768 110 */ 111 public function test_should_return_wp_timestamp() { 112 update_option( 'timezone_string', 'Europe/Kiev' ); 113 114 $datetime = new DateTimeImmutable( 'now', wp_timezone() ); 115 $timestamp = $datetime->getTimestamp(); 116 $wp_timestamp = $timestamp + $datetime->getOffset(); 117 118 $this->assertEquals( $wp_timestamp, date_i18n( 'U' ), 2 ); 119 $this->assertEquals( $timestamp, date_i18n( 'U', false, true ), 2 ); 120 $this->assertEquals( $wp_timestamp, date_i18n( 'U', $wp_timestamp ) ); 121 } 122 123 /** 124 * @ticket 43530 125 */ 126 public function test_swatch_internet_time_with_wp_timestamp() { 127 update_option( 'timezone_string', 'America/Regina' ); 128 129 $this->assertEquals( gmdate( 'B' ), date_i18n( 'B' ) ); 130 } 131 132 /** 133 * @ticket 25768 134 */ 135 public function test_should_handle_escaped_formats() { 136 $format = 'D | \D | \\D | \\\D | \\\\D | \\\\\D | \\\\\\D'; 137 138 $this->assertEquals( gmdate( $format ), date_i18n( $format ) ); 139 } 140 141 /** 142 * @ticket 25768 143 * 144 * @dataProvider dst_times 145 * 146 * @param string $time Time to test in Y-m-d H:i:s format. 147 * @param string $timezone PHP timezone string to use. 148 */ 149 public function test_should_handle_dst( $time, $timezone ) { 150 update_option( 'timezone_string', $timezone ); 151 152 $timezone = new DateTimeZone( $timezone ); 153 $datetime = new DateTime( $time, $timezone ); 154 $wp_timestamp = strtotime( $time ); 155 $format = 'I ' . DATE_RFC3339; 156 157 $this->assertEquals( $datetime->format( $format ), date_i18n( $format, $wp_timestamp ) ); 158 } 159 160 public function dst_times() { 161 return array( 162 'Before DST start' => array( '2019-03-31 02:59:00', 'Europe/Kiev' ), 163 'After DST start' => array( '2019-03-31 04:01:00', 'Europe/Kiev' ), 164 'Before DST end' => array( '2019-10-27 02:59:00', 'Europe/Kiev' ), 165 'After DST end' => array( '2019-10-27 04:01:00', 'Europe/Kiev' ), 166 ); 167 } 110 168 }
Note: See TracChangeset
for help on using the changeset viewer.