Skip to content
This repository has been archived by the owner on Mar 26, 2021. It is now read-only.

Commit

Permalink
Move the DateTimeZone construction into its own separate testable fun…
Browse files Browse the repository at this point in the history
…ction, and write a test for that that iterates over the known valid GMT offsets from WordPress's database.

This is for #52
  • Loading branch information
benlk committed May 23, 2018
1 parent 1459416 commit e87ccb2
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 4 deletions.
42 changes: 38 additions & 4 deletions push_story.php
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ function nprstory_save_nprone_featured( $post_ID ) {
* @param Int $post_ID The post ID of the post we're saving
* @since 1.7
* @see nprstory_publish_meta_box
* @uses nprstory_get_datetimezone
* @link https://en.wikipedia.org/wiki/ISO_8601
*/
function nprstory_save_datetime( $post_ID ) {
Expand All @@ -642,7 +643,7 @@ function nprstory_save_datetime( $post_ID ) {
// If the post is not published and values are not set, save an empty post meta
if ( isset( $date ) && 'publish' === $post->status ) {
$timezone = get_option( 'gmt_offset' );
$datetime = date_create( $date, new DateTimeZone( $timezone ) );
$datetime = date_create( $date, nprstory_get_datetimezone() );
$time = explode( ':', $time );
$datetime->setTime( $time[0], $time[1] );
$value = date_format( $datetime , DATE_ATOM );
Expand All @@ -662,24 +663,57 @@ function nprstory_save_datetime( $post_ID ) {
* @param WP_Post|int $post the post ID or WP_Post object
* @return DateTime the DateTime object created from the post expiry date
* @see note on DATE_ATOM and DATE_ISO8601 https://secure.php.net/manual/en/class.datetime.php#datetime.constants.types
* @uses nprstory_get_datetimezone
* @since 1.7
* @todo rewrite this to use fewer queries, so it's using the WP_Post internally instead of the post ID
*/
function nprstory_get_post_expiry_datetime( $post ) {
$post = ( $post instanceof WP_Post ) ? $post->ID : $post ;
$iso_8601 = get_post_meta( $post, '_nprone_expiry_8601', true );
$timezone = get_option( 'gmt_offset' );
$timezone = nprstory_get_datetimezone();

if ( empty( $iso_8601 ) ) {
// return DateTime for the publish date plus seven days
$future = get_the_date( DATE_ATOM, $post ); // publish date
return date_add( date_create( $future, new DateTimeZone( $timezone ) ), new DateInterval( 'P7D' ) );
return date_add( date_create( $future, $timezone ), new DateInterval( 'P7D' ) );
} else {
// return DateTime for the expiry date
return date_create( $iso_8601, new DateTimeZone( $timezone ) );
return date_create( $iso_8601, $timezone );
}
}

/**
* Helper for getting WordPress GMT offset
*
* It turns out we don't need to do anything with regards to get_option( 'timezone_string' ),
* because WordPress includes wp_timezone_override_offset as a default filter upon
* the filter pre_option_gmt_offset
*
* @since 1.7.2
* @link https://github.com/npr/nprapi-wordpress/issues/52
* @return DateTimeZone
*/
function nprstory_get_datetimezone() {
$timezone = get_option( 'gmt_offset' );

if ( is_numeric( $timezone ) ) {
// Because PHP handles timezone offsets for this purpose in seconds,
// (at least, according to https://secure.php.net/manual/en/datetimezone.getoffset.php)
// we must convert the WordPress-stored decimal hours into seconds. THis value can be positive, negative, or zero.
$offset = floatval( $timezone ) * HOUR_IN_SECONDS;
} // It could also be '' empty string, which is a valid offset for the purposes of DateTimeZone::__construct().

try {
$return = new DateTimeZone( $offset );
} catch( Exception $e ) {
error_log(var_export( $e->getMessage(), true));
nprstory_error_log( $e->getMessage() );
$return = new DateTimeZone( '+0000' ); // The default timezone when WordPress does not have a configured timezone. This will also trigger when the gmt_offset is '0', which is the case when the GMT time is Greenwich Mean Time.
}

return $return;
}

/**
* Add an admin notice to the post editor with the post's error message if it exists
*/
Expand Down
48 changes: 48 additions & 0 deletions tests/test-push_story.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,52 @@ function test_save_send_to_npr_one() {
$this->markTestIncomplete('This test has not been implemented yet.');
}

function test_nprstory_get_datetimezone_all() {

/*
* Get a list of time zones' UTC offsets.
*
* Yes, http://infiniteundo.com/post/25509354022/more-falsehoods-programmers-believe-about-time has been read.
* Yes, https://secure.php.net/manual/en/datetimezone.listabbreviations.php returns some canonically ~weird~ time zones.
* We'll mitigate those later in this test.
*/
$tzdata = DateTimeZone::listAbbreviations();
$zones = array();

// The format of $tzdata groups time zones by general zones.
foreach ( $tzdata as $general => $specific_zones ) {

// We want the offset of each specific zone.
$zones_each = wp_list_pluck( $specific_zones, 'offset' );

// Calculate the string offset format.
foreach ( $zones_each as $seconds ) {
if ( $seconds % 60 === 0 ) { // no fractional minutes
// no 20- or 40-minute offsets; they're valid but WordPress does not consider them.
if ( ( $seconds / 60 ) % 15 === 0 ) {
$zones[] = $seconds / 3600; // WordPress saves time zones as a decimal
}
}
}
}
$zones = array_unique( $zones );
asort( $zones );

// Other test cases
$zones[] = '';

// Run every single test case
foreach ( $zones as $offset ) {
update_option( 'gmt_offset', $offset );
$DateTimeZone = nprstory_get_datetimezone();
$this->assertInstanceOf( DateTimeZone, $DateTimeZone, sprintf(
'%1$s is not an instance of DateTimeZone when DateTimeZone::__construct was called with the timezone %2$s as the wp_options option_key gmt_offset.',
var_export( $DateTimeZone ),
var_export( $offset )
);
}

// reset
delete_option( 'gmt_offset' );
}
}

0 comments on commit e87ccb2

Please sign in to comment.