Unable to select an old date in wordpress

I am unable to set the year below 1899 for a post. If i set year below 1899 it is set to the current year automatically.

screen shot

Read More

I have purchased the Timeline theme and asked in their support forum. They replied:

This sounds like a limitation created by your hosting provider. Nothing in the theme is preventing the date you assign – as you can see, the demo has posts using dates in the 1400s. Try contacting your hosting provider and see if they have any insight on how to address that.

Related posts

2 comments

  1. This is not really an answer, just an attempt to find the specific context for this problem. Please install the following plugin on your site, try to set the three dates and add your result to the second <pre> in the table below.

    /* Plugin Name: WPSE Sysinfo */
    add_action( 'admin_footer', 'wpse_sysinfo' );
    function wpse_sysinfo() {
    
        $bit         = 4 === PHP_INT_SIZE ? 32 : 64; // PHP version, not OS!
        $php_version = PHP_VERSION;
        $db_version  = $GLOBALS['wpdb']->db_version();
    
        print "<pre>$bit | $php_version | $db_version</pre>";
    }
    

    Gist of the Plugin can be checked out here.

    OS           | OS bit | PHP         | PHP Bit | MySQL  | 999  | 1899 | 2020 | 2039 | user
    
    WIN7         |     64 | 5.4.4       | ??      | 5.5.25 |   ✘  |   ✘  |  ✔   |   ✘  | toscho
    Linux        |     ?? | 5.3.18-nmm1 | ??      | 5.1.70 |   ✔  |   ✔  |  ✔   |   ✔  | toscho
    CentOS 6     |     64 | 5.5.4       | ??      | 5.0.95 |   ✔  |   ✔  |  ✔   |   ✔  | toscho
    WIN7         |     64 | 5.4.15      | 32      | 5.5.31 |   ✘  |   ✘  |  ✔   |   ✘  | rarst
    Ubuntu 12.04 |     64 | 5.3.10-1    | 64      | 5.5.32 |   ✔  |   ✔  |  ✔   |   ✔  | Pille
    CloudLinux   |     64 | 5.2.17      | 64      | 5.0.96 |   ✔  |   ✔  |  ✔   |   ✔  | Pille
    Ubuntu 12.10 |     64 | 5.4.6       | 64      | 5.5.32 |   ✔  |   ✔  |  ✔   |   ✔  | Michael Ecklund
    CENTOS 5.9   |     32 | 5.3.27      | 32      | 5.5.32 |   ✘  |   ✘  |  ✔   |   ✘  | Michael Ecklund
    WIN7         |     64 | 5.4.7       | 64      | 5.5.27 |   ✘  |   ✘  |  ✔   |   ✘  | kaiser
    OSX 10.7.5   |     64 | 5.3.6       | 64      | 5.5.9  |   ✔  |   ✔  |  ✔   |   ✔  | GhostToast
    Centos 6.4   |     64 | 5.4.17      | 32      | 5.1.59 |   ✘  |   ✘  |  ✔   |   ✘  | birgire
    Debian 6     |     64 | 5.4.19      | 64      | 5.1.66 |   ✘  |   ✘  |  ✔   |   ✘  | birgire
    WIN7         |     64 | 5.5.0       | 64      | 5.5.22 |   ✘  |   ✘  |  ✔   |   ✘  | G.M.
    OSX 10.7.4   |     64 | 5.3.6       | 64      | 5.5.9  |   ✔  |   ✔  |  ✔   |   ✔  | brasofilo
    CentOS 5     |     64 | 5.3.22      | 64      | 5.1.68 |   ✔  |   ✔  |  ✔   |   ✔  | brasofilo
    Mac 10.8.5   |     64 | 5.3.26      | 64      | 5.5.25 |   ✔  |   ✔  |  ✔   |   ✔  | flentini
    WIN7         |     64 | 5.3.27      | 64      | 5.5.31 |   ✔  |   ✔  |  ✔   |   ✔  | Sascha Krause
    Win7SP1      |     64 | 5.3.8       | 64      | 5.5.28 |   ✔  |   ✔  |  ✔   |   ✔  | Manuel Sychold
    
    1. Create a new post. Save it.
    2. Set the date to Jan. 1st, 0999, click Update. Is it saved or changed to the current date?
    3. Repeat for the date settings for 1899, 2020 and 2039.
    4. Take the information from the plugin output in your admin footer, and update the table.
  2. Question and expectations

    While the literal form of this question is practical in context (year 1899) it is a little vague in theoretical sense. How old is old? How far into the past we might want to go? What about the future?

    Since WordPress had started out as blogging engine, in that contextual sense it evolved to handle following span of time:

    • dates WP existed (obviously to be able to use it)
    • range of possible historical posts (implicitly as far back as Internet existed)
    • as far into future as possible without special effort (work until it breaks)

    As WordPress usage evolved into non-blogging applications such projects (commonly history and art as I have seen from reports) started to hit assorted issues with dates outside of this span.

    For the purpose of my research I had formulated following questions:

    1. What are the two earliest and latest full calendar years, which can be used with WordPress post dates natively and reliably?
    2. What are low hanging fruits (if any) to extend available span beyond native range?

    Platform limitations

    Since WordPress is PHP application and uses MySQL for data storage it’s subject to their limitations.

    MySQL

    WordPress stores post dates in post_date column of DATETIME type in MySQL.

    According to documentation this type supports years 1000 to 9999:

    The DATETIME type is used for values that contain both date and time parts. MySQL retrieves and displays DATETIME values in 'YYYY-MM-DD HH:MM:SS' format. The supported range is '1000-01-01 00:00:00' to '9999-12-31 23:59:59'.

    However it also says that earlier values might work, no mention of later values:

    For the DATE and DATETIME range descriptions, “supported” means that although earlier values might work, there is no guarantee.

    While empirically I have observed values out of range working, this is anecdotal and falls out of our reliability condition.

    PHP

    In PHP programming Unix timestamp representation of date is widely used. According to documentation for our purposes (PHP 5.2+ and generic 32 bit environment) it supports years (in full) 1902 to 2037:

    The valid range of a timestamp is typically from Fri, 13 Dec 1901 20:45:54 UTC to Tue, 19 Jan 2038 03:14:07 UTC. (These are the dates that correspond to the minimum and maximum values for a 32-bit signed integer.) Additionally, not all platforms support negative timestamps, therefore your date range may be limited to no earlier than the Unix epoch. This means that e.g. dates prior to Jan 1, 1970 will not work on Windows, some Linux distributions, and a few other operating systems. PHP 5.1.0 and newer versions overcome this limitation though.

    Other than that newer Date/Time based handling is 64 bit and has range roughly -292 billion to 292 billion years, which probably exceeds humanity needs at this time.

    WordPress limitations

    WordPress introduces and inherits some additional limitation in its code base.

    Data flow

    From basic user workflow point of view there are two processed related to date:

    • date input in post edit form must be correctly processed and saved in database
    • date saved in database must be correctly read and shown in interface

    Note that these are technically completely different and independent processes. As further explained their ranges do not overlap and saving correct date does not equal ability to correctly read it in WordPress environment.

    Explicit limits

    • WordPress post editor in admin allows range of years, that can be submitted as post date, 100 to 9999
    • _wp_translate_postdata() processes year (submitted as distinct number from form) and:
      • sanitizes it to non-negative >0
      • validates it using wp_checkdate(), which calls PHP native checkdate(), which imposes limit of 1 to 32767

    Implicit limits

    • strtotime() PHP function is used multiple times and is subject to above mentioned Unix timestamp, at the lowest level in mysql2date() that affects all reads of dates from database, 1902 to 2037 range inherited
    • WordPress falls back to regular expression for date parsing in get_gmt_from_date(), which expects year to be ([0-9]{1,4}), limiting it 1 to 9999, strong possibility of similar processing in other functions that will require more thorough code audit to be enumerated

    Possibility of workarounds

    • wp_checkdate() has wp_checkdate filter, which allows to override this validation check
    • output aimed at end-user goes through date_i18n() which has date_i18n filter, theoretically allows to completely intercept and re-process output of dates to interface however challenging if function is passed already out of range (false) timestamp input

    Conclusions

    For the practical purposes and portability of data WordPress post date range seems to be equal to that of 32 bit Unix timestamp and consist of years 1902 to 2037 inclusively.

    For any post date operation out of this range environment must be audited (64 bit range of Unix timestamps, de-facto functioning MySQL or alternate database storage for the values). For farther ranges (below 1000, above 9999) considerable amounts of custom code are likely to be required.

    For any implementation of arbitrary dates it makes sense to:

    • store them in MySQL in format not subject to database limitations
    • process in PHP using completely custom Date/Time-based code and/or WordPress functions audited not to be affected by Unix timestamp limits

    Code test bed

    The following code and hand picked set of years have been used for research above and testing of conclusions:

    require ABSPATH . '/wp-admin/includes/post.php';
    
    $timestamp_size_info = array(
        'PHP_INT_SIZE'   => PHP_INT_SIZE,
        'PHP_INT_MAX'    => number_format( PHP_INT_MAX ),
        'min timestamp'  => date( DATE_ISO8601, - PHP_INT_MAX ),
        'zero timestamp' => date( DATE_ISO8601, 0 ),
        'max timestamp'  => date( DATE_ISO8601, PHP_INT_MAX ),
    );
    
    r( $timestamp_size_info );
    
    // hand picked set of years to test for assorted limits
    $years = array(
        'negative'           => - 1,
        'zero'               => 0,
        'one'                => 1,
        'wp min'             => 100,
        'mysql first'        => 1000,
        'before unix'        => 1899,
        'unix first'         => 1902,
        'current'            => 2013,
        'unix last'          => 2037,
        'after unix'         => 2039,
        'mysql last, wp max' => 9999,
        'after checkdate'    => 33000,
    );
    
    // simulates form submission data
    $post = array(
        'post_type' => 'post', // shut notice
        'edit_date' => 1,
        'aa'        => 1,
        'mm'        => '01',
        'jj'        => '01',
        'hh'        => '00',
        'mn'        => '00',
        'ss'        => '00',
    );
    
    // add_filter( 'wp_checkdate', '__return_true' );
    
    foreach ( $years as $name => $year ) {
    
        $post['aa'] = $year;
        $translated = _wp_translate_postdata( false, $post );
    
        if ( is_wp_error( $translated ) ) { // wp_checkdate() failed
            r( array( 'year' => $year . " ({$name})", 'translated valid' => false ) );
        }
        else {
    
            $post_date        = $translated['post_date'];
            $post_date_gmt    = $translated['post_date_gmt'];
            $translated_valid = (string) $year == substr( $post_date, 0, strpos( $post_date, '-' ) );
            $mysql2date       = mysql2date( DATE_ISO8601, $post_date );
            $mysql2date_valid = (string) $year == substr( $mysql2date, 0, strpos( $mysql2date, '-' ) );
    
            r( array(
                'year'             => $year . " ({$name})",
                'post_date'        => $post_date,
                'translated valid' => $translated_valid,
                'post_date_gmt'    => $post_date_gmt,
                'mysql2date'       => $mysql2date,
                'from sql valid'   => $mysql2date_valid,
            ) );
        }
    }
    

Comments are closed.