Make WordPress Core

Opened 6 months ago

Last modified 5 months ago

#63772 new defect (bug)

get_calendar() shows incorrect month-end due to current_time() timezone issue

Reported by: smilkobutawp's profile smilkobutawp Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 6.8.2
Component: Date/Time Keywords: has-patch 2nd-opinion
Focuses: Cc:

Description

The get_calendar() function in WordPress incorrectly calculates the number of days in the current month when the site timezone is set to UTC+9 (e.g., Asia/Tokyo) and the current time is near the end of the month (e.g., July 31st around 22:00–23:59 JST).
🔁 Steps to Reproduce:

  1. Set your WordPress site timezone to Asia/Tokyo (UTC+9).
  1. Visit a page that displays the default calendar widget.
  1. On July 31, 2025, at 22:37 JST, observe that the calendar for July only shows up to the 30th, even though July has 31 days.
  1. Inspect wp-includes/general-template.php, where get_calendar() uses the following:

$thisyear = (int) current_time( 'Y' );
$thismonth = (int) current_time( 'm' );
$unixmonth = mktime( 0, 0, 0, $thismonth, 1, $thisyear );
$last_day = gmdate( 't', $unixmonth );

This calculation yields an incorrect $thismonth = 8 (August), causing $last_day = 30 instead of 31 for July.
🧠 Technical Cause:

current_time('Y') and current_time('m') are localized string values, but they are influenced by UTC time logic internally, especially near the date change boundary. As a result, the calendar may "roll over" to the next month prematurely.
✅ Suggested Fix:

Use current_time('timestamp') or better yet, rely on the correct timezone-aware approach using wp_timezone():

$dt = new DateTimeImmutable( 'now', wp_timezone() );
$thisyear = (int) $dt->format( 'Y' );
$thismonth = (int) $dt->format( 'm' );
$unixmonth = $dt->setDate( $thisyear, $thismonth, 1 )->getTimestamp();
$last_day = gmdate( 't', $unixmonth );

✅ Confirmed Result:

On 2025-07-31 22:37 JST, this code correctly yields:

$thisyear = 2025
$thismonth = 7
$last_day = 31

This provides accurate calendar generation behavior, aligned with local timezone settings.

Please consider updating get_calendar() to use timezone-aware logic in future versions to prevent subtle bugs in calendar rendering for international users.

Attachments (1)

wp_calendar1.png (59.4 KB) - added by smilkobutawp 6 months ago.

Download all attachments as: .zip

Change History (9)

This ticket was mentioned in PR #9366 on WordPress/wordpress-develop by @naveendwivedi.


6 months ago
#1

  • Keywords has-patch added; needs-patch removed

This ticket was mentioned in PR #9367 on WordPress/wordpress-develop by @naveendwivedi.


6 months ago
#2

fixed bug for Calculation Day of the month

Trac ticket: https://core.trac.wordpress.org/ticket/63772

@naveendwivedi commented on PR #9367:


6 months ago
#3

i am closing this PR

@naveendwivedi commented on PR #9366:


6 months ago
#4

I am closing this PR

This ticket was mentioned in PR #9371 on WordPress/wordpress-develop by @naveendwivedi.


6 months ago
#5

fix calendar bug calculated correct date of the month
Trac ticket: https://core.trac.wordpress.org/ticket/63772

This ticket was mentioned in PR #9372 on WordPress/wordpress-develop by @naveendwivedi.


6 months ago
#6

addded current date as dynamic value and passed in function mktime
Trac ticket: https://core.trac.wordpress.org/ticket/63772

This ticket was mentioned in PR #9373 on WordPress/wordpress-develop by @naveendwivedi.


6 months ago
#7

added current day as dynamic value and passed into mktime function

Trac ticket: https://core.trac.wordpress.org/ticket/63772

#8 in reply to: ↑ description @autotutorial
5 months ago

  • Keywords 2nd-opinion added

Replying to smilkobutawp:

The get_calendar() function in WordPress incorrectly calculates the number of days in the current month when the site timezone is set to UTC+9 (e.g., Asia/Tokyo) and the current time is near the end of the month (e.g., July 31st around 22:00–23:59 JST).
🔁 Steps to Reproduce:

  1. Set your WordPress site timezone to Asia/Tokyo (UTC+9).
  1. Visit a page that displays the default calendar widget.
  1. On July 31, 2025, at 22:37 JST, observe that the calendar for July only shows up to the 30th, even though July has 31 days.
  1. Inspect wp-includes/general-template.php, where get_calendar() uses the following:

$thisyear = (int) current_time( 'Y' );
$thismonth = (int) current_time( 'm' );
$unixmonth = mktime( 0, 0, 0, $thismonth, 1, $thisyear );
$last_day = gmdate( 't', $unixmonth );

This calculation yields an incorrect $thismonth = 8 (August), causing $last_day = 30 instead of 31 for July.
🧠 Technical Cause:

current_time('Y') and current_time('m') are localized string values, but they are influenced by UTC time logic internally, especially near the date change boundary. As a result, the calendar may "roll over" to the next month prematurely.
✅ Suggested Fix:

Use current_time('timestamp') or better yet, rely on the correct timezone-aware approach using wp_timezone():

$dt = new DateTimeImmutable( 'now', wp_timezone() );
$thisyear = (int) $dt->format( 'Y' );
$thismonth = (int) $dt->format( 'm' );
$unixmonth = $dt->setDate( $thisyear, $thismonth, 1 )->getTimestamp();
$last_day = gmdate( 't', $unixmonth );

✅ Confirmed Result:

On 2025-07-31 22:37 JST, this code correctly yields:

$thisyear = 2025
$thismonth = 7
$last_day = 31

This provides accurate calendar generation behavior, aligned with local timezone settings.

Please consider updating get_calendar() to use timezone-aware logic in future versions to prevent subtle bugs in calendar rendering for international users.

WordPress sets UTC timezone as default and the mktime function also used UTC. https://github.com/WordPress/WordPress/blob/master/wp-settings.php#L72 If the theme, plugin or anything else is different from UTC it is not a CORE WordPress bug.

<?php

$original = date_default_timezone_set( 'Europe/Berlin');
$WordPress = date_default_timezone_set('UTC');
$tz = timezone_open( 'Asia/Tokyo' );
$date = date_create( '2025-07-30 22:30:00', $tz );
$thisyear = (int) date_format( $date,  'Y' );
$thismonth = (int) date_format( $date, 'm' );
$unixmonth = mktime( 0, 0, 0, $thismonth, 1, $thisyear ); // if set Europe/Berlin 1751320800 (+02:00)
$last_day = gmdate( 't', $unixmonth );
var_dump($unixmonth, $thismonth, $last_day, $WordPress);
?>
Last edited 5 months ago by autotutorial (previous) (diff)
Note: See TracTickets for help on using tickets.