Ticket #25768: date-i18n.patch
| File date-i18n.patch, 9.7 KB (added by , 7 years ago) |
|---|
-
src/wp-includes/functions.php
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8
81 81 * take over the format for the date. If it isn't, then the date format string 82 82 * will be used instead. 83 83 * 84 * Note that due to the way WP typically generates a sum of timestamp and offset with `strtotime()` 85 * it implies offset added at a _current_ time, not at the time which timestamp represents. 86 * Storing such timestamps or calculating them differently will lead to invalid output. 87 * 84 88 * @since 0.71 85 89 * 86 90 * @global WP_Locale $wp_locale … … 106 110 * See https://core.trac.wordpress.org/ticket/9396 107 111 */ 108 112 $req_format = $dateformatstring; 113 $new_format = ''; 109 114 110 $dateformatstring = preg_replace( '/(?<!\\\\)c/', DATE_W3C, $dateformatstring );115 // We need to unpack shorthand `r` format because it has parts that might be localized. 111 116 $dateformatstring = preg_replace( '/(?<!\\\\)r/', DATE_RFC2822, $dateformatstring ); 112 117 113 if ( ( ! empty( $wp_locale->month ) ) && ( ! empty( $wp_locale->weekday ) ) ) { 114 $datemonth = $wp_locale->get_month( gmdate( 'm', $i ) ); 115 $datemonth_abbrev = $wp_locale->get_month_abbrev( $datemonth ); 116 $dateweekday = $wp_locale->get_weekday( gmdate( 'w', $i ) ); 117 $dateweekday_abbrev = $wp_locale->get_weekday_abbrev( $dateweekday ); 118 $datemeridiem = $wp_locale->get_meridiem( gmdate( 'a', $i ) ); 119 $datemeridiem_capital = $wp_locale->get_meridiem( gmdate( 'A', $i ) ); 120 $dateformatstring = ' ' . $dateformatstring; 121 $dateformatstring = preg_replace( '/([^\\\])D/', "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring ); 122 $dateformatstring = preg_replace( '/([^\\\])F/', "\\1" . backslashit( $datemonth ), $dateformatstring ); 123 $dateformatstring = preg_replace( '/([^\\\])l/', "\\1" . backslashit( $dateweekday ), $dateformatstring ); 124 $dateformatstring = preg_replace( '/([^\\\])M/', "\\1" . backslashit( $datemonth_abbrev ), $dateformatstring ); 125 $dateformatstring = preg_replace( '/([^\\\])a/', "\\1" . backslashit( $datemeridiem ), $dateformatstring ); 126 $dateformatstring = preg_replace( '/([^\\\])A/', "\\1" . backslashit( $datemeridiem_capital ), $dateformatstring ); 118 /** 119 * Timestamp with offset is typically produced by a UTC `strtotime()` call on an input without time zone. 120 * 121 * This is the best attempt to reverse that operation into a local time to use. 122 */ 123 $local_time = gmdate( 'Y-m-d H:i:s', $i ); 124 $gmt_mode = $gmt && ( false === $timestamp_with_offset ); 125 $timezone = $gmt_mode ? new DateTimeZone( 'UTC' ) : wp_timezone(); 126 $datetime = date_create( $local_time, $timezone ); 127 127 128 $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) - 1 ); 128 /** 129 * This is a legacy implementation quirk that returned timestamp is also with offset. 130 * 131 * Ideally this function should never be used to produce a timestamp. 132 */ 133 $timestamp_mode = 'U' === $dateformatstring; 134 135 if ( $timestamp_mode ) { 136 $new_format = $i; 129 137 } 130 $timezone_formats = array( 'P', 'I', 'O', 'T', 'Z', 'e' );131 $timezone_formats_re = implode( '|', $timezone_formats );132 if ( preg_match( "/$timezone_formats_re/", $dateformatstring ) ) {133 $timezone_string = get_option( 'timezone_string' );134 if ( false === $timestamp_with_offset && $gmt ) {135 $timezone_string = 'UTC';136 }137 if ( $timezone_string ) {138 $timezone_object = timezone_open( $timezone_string );139 $date_object = date_create( null, $timezone_object );140 foreach ( $timezone_formats as $timezone_format ) {141 if ( false !== strpos( $dateformatstring, $timezone_format ) ) {142 $formatted = date_format( $date_object, $timezone_format );143 $dateformatstring = ' ' . $dateformatstring;144 $dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring );145 $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) - 1 );146 }147 }148 } else {149 $offset = get_option( 'gmt_offset' );150 foreach ( $timezone_formats as $timezone_format ) {151 if ( 'I' === $timezone_format ) {152 continue;153 }154 138 155 if ( false !== strpos( $dateformatstring, $timezone_format ) ) { 156 if ( 'Z' === $timezone_format ) { 157 $formatted = (string) ( $offset * HOUR_IN_SECONDS ); 158 } else { 159 $prefix = ''; 160 $hours = (int) $offset; 161 $separator = ''; 162 $minutes = abs( ( $offset - $hours ) * 60 ); 139 if ( ! $timestamp_mode && ( ! empty( $wp_locale->month ) ) && ( ! empty( $wp_locale->weekday ) ) ) { 140 $month = $wp_locale->get_month( $datetime->format( 'm' ) ); 141 $weekday = $wp_locale->get_weekday( $datetime->format( 'w' ) ); 163 142 164 if ( 'T' === $timezone_format ) { 165 $prefix = 'GMT'; 166 } elseif ( 'e' === $timezone_format || 'P' === $timezone_format ) { 167 $separator = ':'; 168 } 143 $format_length = strlen( $dateformatstring ); 169 144 170 $formatted = sprintf( '%s%+03d%s%02d', $prefix, $hours, $separator, $minutes ); 171 } 145 for ( $i = 0; $i < $format_length; $i ++ ) { 146 switch ( $dateformatstring[ $i ] ) { 147 case 'D': 148 $new_format .= backslashit( $wp_locale->get_weekday_abbrev( $weekday ) ); 149 break; 150 case 'F': 151 $new_format .= backslashit( $month ); 152 break; 153 case 'l': 154 $new_format .= backslashit( $weekday ); 155 break; 156 case 'M': 157 $new_format .= backslashit( $wp_locale->get_month_abbrev( $month ) ); 158 break; 159 case 'a': 160 $new_format .= backslashit( $wp_locale->get_meridiem( $datetime->format( 'a' ) ) ); 161 break; 162 case 'A': 163 $new_format .= backslashit( $wp_locale->get_meridiem( $datetime->format( 'A' ) ) ); 164 break; 165 case '\\': 166 $new_format .= $dateformatstring[ $i ]; 172 167 173 $dateformatstring = ' ' . $dateformatstring; 174 $dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring ); 175 $dateformatstring = substr( $dateformatstring, 1 ); 176 } 168 // If character follows slash we add it without translating. 169 if ( $i < $format_length ) { 170 $new_format .= $dateformatstring[ ++ $i ]; 171 } 172 break; 173 default: 174 $new_format .= $dateformatstring[ $i ]; 175 break; 177 176 } 178 177 } 179 178 } 180 $j = @gmdate( $dateformatstring, $i ); 179 180 $j = $datetime->format( $new_format ); 181 181 182 182 /** 183 183 * Filters the date formatted based on the locale. -
tests/phpunit/tests/date/dateI18n.php
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8
6 6 */ 7 7 class Tests_Date_I18n extends WP_UnitTestCase { 8 8 public function test_should_format_date() { 9 update_option( 'timezone_string', 'UTC' ); 10 9 11 $this->assertEquals( strtotime( gmdate( 'Y-m-d H:i:s' ) ), strtotime( date_i18n( 'Y-m-d H:i:s' ) ), 'The dates should be equal', 2 ); 10 12 } 11 13 … … 17 19 $this->assertEquals( strtotime( gmdate( DATE_RFC3339 ) ), strtotime( date_i18n( DATE_RFC3339, false, true ) ), 'The dates should be equal', 2 ); 18 20 } 19 21 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 }23 24 22 public function test_custom_timezone_setting() { 25 23 update_option( 'timezone_string', 'America/Regina' ); 26 24 … … 107 105 ), 108 106 ); 109 107 } 108 109 public function test_should_return_wp_timestamp() { 110 111 update_option( 'timezone_string', 'Europe/Kiev' ); 112 113 $datetime = new DateTimeImmutable( 'now', wp_timezone() ); 114 $timestamp = $datetime->getTimestamp(); 115 $wp_timestamp = $timestamp + $datetime->getOffset(); 116 117 $this->assertEquals( $wp_timestamp, date_i18n( 'U' ), 2 ); 118 $this->assertEquals( $timestamp, date_i18n( 'U', false, true ), 2 ); 119 $this->assertEquals( $wp_timestamp, date_i18n( 'U', $wp_timestamp ) ); 120 } 121 122 /** 123 * @link https://core.trac.wordpress.org/ticket/43530 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 public function test_should_handle_escaped_formats() { 133 134 $format = 'D | \D | \\D | \\\D | \\\\D | \\\\\D | \\\\\\D'; 135 136 $this->assertEquals( gmdate( $format ), date_i18n( $format ) ); 137 } 138 139 /** 140 * @dataProvider dst_times 141 * 142 * @param string $time Time to test in Y-m-d H:i:s format. 143 * @param string $tmezone PHP time zone string to use. 144 */ 145 public function test_should_handle_dst( $time, $timezone ) { 146 147 update_option( 'timezone_string', $timezone ); 148 149 $timezone = new DateTimeZone( $timezone ); 150 $datetime = new DateTime( $time, $timezone ); 151 $wp_timestamp = strtotime( $time ); 152 $format = 'I ' . DATE_RFC3339; 153 154 $this->assertEquals( $datetime->format( $format ), date_i18n( $format, $wp_timestamp ) ); 155 } 156 157 public function dst_times() { 158 return [ 159 'Before DST start' => [ '2019-03-31 02:59:00', 'Europe/Kiev' ], 160 'After DST start' => [ '2019-03-31 04:01:00', 'Europe/Kiev' ], 161 'Before DST end' => [ '2019-10-27 02:59:00', 'Europe/Kiev' ], 162 'After DST end' => [ '2019-10-27 04:01:00', 'Europe/Kiev' ], 163 ]; 164 } 110 165 }