Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a test for local times saved across DST change #761

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion php/class-fieldmanager-datepicker.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,38 @@ public function __construct( $label = '', $options = array() ) {
}
}

/**
* Get the current site's local timezone as a DateTimeZone.
*
* This is a wrapper/shim for `wp_timezone()`, introduced in WordPress 5.3.
*
* @return \DateTimeZone
*/
protected function get_local_datetimezone() {
if ( function_exists( 'wp_timezone' ) ) {
return wp_timezone();
}

/* If wp_timezone() isn't available, shim it. */

$timezone_string = get_option( 'timezone_string' );

if ( $timezone_string ) {
return new \DateTimeZone( $timezone_string );
}

$offset = (float) get_option( 'gmt_offset' );
$hours = (int) $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 );

return new \DateTimeZone( $tz_offset );
}

/**
* Generate HTML for the form element itself. Generally should be just one tag, no wrappers.
*
Expand All @@ -96,7 +128,8 @@ public function form_element( $value ) {
// to alter the timestamp. This isn't ideal, but there currently isn't a good way around
// it in WordPress.
if ( $this->store_local_time ) {
$value += get_option( 'gmt_offset' ) * HOUR_IN_SECONDS;
$tz = $this->get_local_datetimezone();
$value = $value + $tz->getOffset( new DateTime( "@{$value}" ) );
}
ob_start();
include fieldmanager_get_template( 'datepicker' );
Expand Down
68 changes: 52 additions & 16 deletions tests/php/test-fieldmanager-datepicker-field.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,8 @@ public function setUp() {
parent::setUp();
Fieldmanager_Field::$debug = true;

$this->post = array(
'post_status' => 'publish',
'post_content' => rand_str(),
'post_title' => rand_str(),
);

// insert a post
$this->post_id = wp_insert_post( $this->post );
$this->post_id = self::factory()->post->create();
}

/**
Expand Down Expand Up @@ -48,7 +42,7 @@ public function test_before_1970s_date() {
),
);

$base->add_meta_box( 'test meta box', $this->post )->save_to_post_meta( $this->post_id, $test_data['test_date_group'] );
$base->add_meta_box( 'test meta box', 'post' )->save_to_post_meta( $this->post_id, $test_data['test_date_group'] );

$saved_data = get_post_meta( $this->post_id, 'test_date_group', true );
$input_element = $date_picker->form_element( $saved_data['test_date_field'] );
Expand Down Expand Up @@ -83,7 +77,7 @@ public function test_time_feature() {
),
),
);
$base->add_meta_box( 'test meta box', $this->post )->save_to_post_meta( $this->post_id, $test_data['test_datetime_group'] );
$base->add_meta_box( 'test meta box', 'post' )->save_to_post_meta( $this->post_id, $test_data['test_datetime_group'] );
$saved_data = get_post_meta( $this->post_id, 'test_datetime_group', true );
$this->assertEmpty( $saved_data['test_datetime_field'] );

Expand All @@ -98,7 +92,7 @@ public function test_time_feature() {
),
),
);
$base->add_meta_box( 'test meta box', $this->post )->save_to_post_meta( $this->post_id, $test_data['test_datetime_group'] );
$base->add_meta_box( 'test meta box', 'post' )->save_to_post_meta( $this->post_id, $test_data['test_datetime_group'] );
$saved_data = get_post_meta( $this->post_id, 'test_datetime_group', true );
$this->assertEquals( strtotime( '13 Mar 2014' ), $saved_data['test_datetime_field'] );

Expand All @@ -113,7 +107,7 @@ public function test_time_feature() {
),
),
);
$base->add_meta_box( 'test meta box', $this->post )->save_to_post_meta( $this->post_id, $test_data['test_datetime_group'] );
$base->add_meta_box( 'test meta box', 'post' )->save_to_post_meta( $this->post_id, $test_data['test_datetime_group'] );
$saved_data = get_post_meta( $this->post_id, 'test_datetime_group', true );
$this->assertEquals( strtotime( '2:37 am' ), $saved_data['test_datetime_field'] );

Expand All @@ -128,7 +122,7 @@ public function test_time_feature() {
),
),
);
$base->add_meta_box( 'test meta box', $this->post )->save_to_post_meta( $this->post_id, $test_data['test_datetime_group'] );
$base->add_meta_box( 'test meta box', 'post' )->save_to_post_meta( $this->post_id, $test_data['test_datetime_group'] );
$saved_data = get_post_meta( $this->post_id, 'test_datetime_group', true );
$this->assertEquals( strtotime( '13 Mar 2014 2:00am' ), $saved_data['test_datetime_field'] );

Expand All @@ -143,7 +137,7 @@ public function test_time_feature() {
),
),
);
$base->add_meta_box( 'test meta box', $this->post )->save_to_post_meta( $this->post_id, $test_data['test_datetime_group'] );
$base->add_meta_box( 'test meta box', 'post' )->save_to_post_meta( $this->post_id, $test_data['test_datetime_group'] );
$saved_data = get_post_meta( $this->post_id, 'test_datetime_group', true );
$this->assertEquals( strtotime( '13 Mar 2014 2:37am' ), $saved_data['test_datetime_field'] );

Expand All @@ -158,7 +152,7 @@ public function test_time_feature() {
),
),
);
$base->add_meta_box( 'test meta box', $this->post )->save_to_post_meta( $this->post_id, $test_data['test_datetime_group'] );
$base->add_meta_box( 'test meta box', 'post' )->save_to_post_meta( $this->post_id, $test_data['test_datetime_group'] );
$saved_data = get_post_meta( $this->post_id, 'test_datetime_group', true );
$this->assertEquals( '', $saved_data['test_datetime_field'] );
}
Expand Down Expand Up @@ -187,15 +181,57 @@ public function test_local_time() {
'ampm' => 'am',
);

$gmt_base->add_meta_box( 'test meta box', $this->post )->save_to_post_meta( $this->post_id, $test_data );
$gmt_base->add_meta_box( 'test meta box', 'post' )->save_to_post_meta( $this->post_id, $test_data );
$gmt_stamp = get_post_meta( $this->post_id, 'test_gmt_time', true );
$this->assertEquals( strtotime( '2014-03-13 02:37:00' ), intval( $gmt_stamp ) );

$local_base->add_meta_box( 'test meta box', $this->post )->save_to_post_meta( $this->post_id, $test_data );
$local_base->add_meta_box( 'test meta box', 'post' )->save_to_post_meta( $this->post_id, $test_data );
$local_stamp = get_post_meta( $this->post_id, 'test_local_time', true );
$this->assertEquals( get_gmt_from_date( '2014-03-13 02:37:00', 'U' ), intval( $local_stamp ) );
$this->assertEquals( strtotime( '2014-03-13 02:37:00 America/New_York' ), intval( $local_stamp ) );

$this->assertEquals( $gmt_stamp - $local_stamp, -4 * HOUR_IN_SECONDS );
}

public function test_local_time_after_time_change() {
update_option( 'timezone_string', 'America/New_York' );

$local_base = new Fieldmanager_Datepicker(
array(
'name' => 'test_local_time',
'use_time' => true,
'store_local_time' => true,
)
);

// Determine when the next time shift is.
$tz = new DateTimeZone( 'America/New_York' );
$transitions = $tz->getTransitions( time(), strtotime( '+1 year' ) );
// Add a day to the time change timestamp for the test timestamp.
$test_timestamp = $transitions[1]['ts'] + DAY_IN_SECONDS;

// Create a DateTime object for noon of the day after the change, in ET.
$test_time = new \DateTime( "@{$test_timestamp}" );
$test_time->setTimezone( $tz );
$test_time->setTime( 12, 0 );

$test_data = array(
'date' => $test_time->format('j M Y' ),
'hour' => '12',
'minute' => '00',
'ampm' => 'pm',
);

// Save the data and ensure that it converts properly.
$local_base->add_meta_box( 'test meta box', 'post' )->save_to_post_meta( $this->post_id, $test_data );
$local_stamp = get_post_meta( $this->post_id, 'test_local_time', true );
$this->assertSame( $test_time->getTimestamp(), (int) $local_stamp );

// Load the markup and ensure that the time converted back properly.
$markup = $local_base->form_element( $local_stamp );
$this->assertContains(
'<input class="fm-element fm-datepicker-time" type="text" value="12" name="test_local_time[hour]" />',
$markup
);
}
}