Питання та очікування
Хоча буквальна форма цього питання практична в контексті (рік 1899), в теоретичному сенсі вона є дещо невиразною. Скільки років? Як далеко в минуле ми могли б хотіти піти? Що з майбутнім?
З тих пір, як WordPress почав функціонувати як блог, в цьому контекстному сенсі він перетворився на наступний проміжок часу:
- дати існування WP (очевидно, щоб мати можливість використовувати його)
- діапазон можливих історичних публікацій (неявно, до тих пір, як існував Інтернет)
- якомога далі в майбутнє без особливих зусиль (працюйте, поки вона не зламається)
У міру того, як використання WordPress перетворювалося на додатки, що не блогують, такі проекти (як правило, історія та мистецтво, як я бачив у звітах) почали стикатися з різними проблемами з датами поза цим періодом.
Для мого дослідження я сформулював такі питання:
- Які два найдавніші та останні повні календарні роки, які можна використовувати з датами публікації WordPress споконвічно та надійно?
- Які низько висячі фрукти (якщо такі є), щоб розширити доступний проміжок за межі рідного асортименту?
Обмеження платформи
Оскільки WordPress є програмою PHP і використовує MySQL для зберігання даних, це обмежується їх обмеженнями.
MySQL
WordPress зберігає дати публікації у post_date
стовпці DATETIME
типу в MySQL.
Відповідно до документації, цей тип підтримує роки від 1000 до 9999 :
DATETIME
Типу використовуються для значень , які містять як дату і час частина. MySQL отримує та відображає DATETIME
значення у 'YYYY-MM-DD HH:MM:SS'
форматі. Підтримується діапазон '1000-01-01 00:00:00'
до '9999-12-31 23:59:59'
.
Однак він також говорить про те, що більш ранні значення можуть працювати, не згадуючи про пізніші значення:
Для DATE and DATETIME
описів діапазону "підтримується" означає, що хоча попередні значення можуть працювати, гарантії немає.
Хоча емпірично я спостерігав значення поза межами діапазону, це анекдотично і випадає з нашого стану надійності.
PHP
У програмуванні PHP широко використовується уявлення часових позначок Unix. Відповідно до документації для наших цілей (PHP 5.2+ та загальне 32-бітове середовище), він підтримує роки (у повному обсязі) з 1902 по 2037 рік :
Дійсний діапазон часової позначки, як правило, від Fri, 13 Dec 1901 20:45:54 UTC
до Tue, 19 Jan 2038 03:14:07 UTC
. (Це дати, які відповідають мінімальному та максимальному значенню для 32-бітного цілого числа, підписаного.) Крім того, не всі платформи підтримують негативні часові позначки, тому діапазон дат може бути обмежений не раніше епохи Unix. Це означає, що, наприклад, дати до Jan 1, 1970
цього не працюватимуть у Windows, деяких дистрибутивах Linux та кількох інших операційних системах. PHP 5.1.0 і новіші версії подолали це обмеження.
Окрім того, що більш нове Date/Time
керування має 64 біт і має діапазон приблизно від -292 мільярдів до 292 мільярдів років , що, ймовірно, перевищує потреби людства в цей час.
Обмеження WordPress
WordPress вводить і успадковує деякі додаткові обмеження у своїй кодовій базі.
Потік даних
З точки зору базового робочого процесу користувача, є два оброблені, пов'язані з датою:
- Введення дати у формі редагування публікації має бути правильно оброблено та збережено у базі даних
- Дата, збережена в базі даних, повинна бути правильно прочитана та показана в інтерфейсі
Зауважте, що це технічно абсолютно різні та незалежні процеси. Як пояснено далі, їхні діапазони не перетинаються, а збереження правильної дати не дорівнює можливості правильного читання в середовищі WordPress.
Явні обмеження
- WordPress пошта редактор в адміністраторі дозволяє діапазон років, які можуть бути представлені як дата публікації, від 100 до 9999
_wp_translate_postdata()
рік процесів (подається як окреме число від форми) та:
- саніфікує його до негативного > 0
- перевіряє його за допомогою
wp_checkdate()
, який викликає PHP native checkdate()
, що встановлює ліміт від 1 до 32767
Неявні межі
strtotime()
Функція PHP використовується декілька разів і підпорядковується вищезазначеній часовій позначці Unix, на найнижчому рівні, mysql2date()
що впливає на всі читання дат із бази даних, діапазон 1902 - 2037 успадковується
- WordPress повертається до регулярного вираження для розбору дат у
get_gmt_from_date()
, який, як очікується, буде роком ([0-9]{1,4})
, обмежуючи його від 1 до 9999 , великою можливістю подібної обробки в інших функціях, які потребують більш ретельного аудиту коду для перерахування
Можливість обходу
wp_checkdate()
має wp_checkdate
фільтр, який дозволяє замінити цю перевірку перевірки
- вихід, спрямований на кінцевого споживача, проходить через
date_i18n()
який має date_i18n
фільтр, теоретично дозволяє повністю перехоплювати та повторно обробляти виведення дат на інтерфейс, однак складним, якщо функція передана вже поза діапазоном ( false
) введення часових позначок
Висновки
Для практичних цілей і портативності даних діапазон дат після WordPress, схоже, дорівнює 32-бітовій часовій позначці Unix і складається з 1902 по 2037 роки включно .
Для будь-якої операції після дати поза цим середовищем діапазону необхідно перевірити (64-бітний діапазон часових позначок Unix, фактично функціонуючий MySQL або альтернативне зберігання бази даних для значень). Для подальших діапазонів ( нижче 1000, вище 9999 ), ймовірно, знадобиться значна кількість користувацького коду.
Для будь-якої реалізації довільних дат має сенс:
- зберігати їх у MySQL у форматі, що не обмежується обмеженнями в базі даних
- обробляти в PHP, використовуючи повністю користувальницький
Date/Time
код та / або функції WordPress, піддані аудиту, на які не впливають обмеження часових позначок Unix
Код тестового ліжка
Для дослідження та перевірки висновків було використано наступний код та вибраний набір років:
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,
) );
}
}