aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/lib/lib_date.php
diff options
context:
space:
mode:
authorAlexandre Alapetite <alexandre@alapetite.fr>2014-06-01 14:40:38 +0200
committerAlexandre Alapetite <alexandre@alapetite.fr>2014-06-01 14:40:38 +0200
commitecac55d3d36dbb0af1c8b5d190972adebee42434 (patch)
tree65b9a776c966f5dee599f8d1b6e627c5529476a9 /lib/lib_date.php
parent08ceeb1bcdb866b9a53da542362d57bc2b7fe935 (diff)
downloadfreshrss-ecac55d3d36dbb0af1c8b5d190972adebee42434.tar.gz
freshrss-ecac55d3d36dbb0af1c8b5d190972adebee42434.zip
New search system, including date: and pubdate: and combination
Now also accepts combination of #tag and intitle: and inurl: and author: and the new date: and pubdate: https://github.com/marienfressinaud/FreshRSS/issues/511 Each search prefix stop at the first space (we should add a possibility to have quotes for multiple words) So if you want two words in title, write "intitle:word1 intitle:word2" Examples of dates: date:2014 date:2014-02/2014-04 or date:201402/201404 date:P1W for the last week
Diffstat (limited to 'lib/lib_date.php')
-rw-r--r--lib/lib_date.php130
1 files changed, 130 insertions, 0 deletions
diff --git a/lib/lib_date.php b/lib/lib_date.php
new file mode 100644
index 000000000..ab7975852
--- /dev/null
+++ b/lib/lib_date.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ * Author: Alexandre Alapetite http://alexandre.alapetite.fr
+ * 2014-06-01
+ * License: GNU AGPLv3 http://www.gnu.org/licenses/agpl-3.0.html
+ *
+ * Parser of ISO 8601 time intervals http://en.wikipedia.org/wiki/ISO_8601#Time_intervals
+ * Examples: "2014-02/2014-04", "2014-02/04", "2014-06", "P1M"
+ */
+
+/*
+example('2014-03');
+example('201403');
+example('2014-03-30');
+example('2014-05-30T13');
+example('2014-05-30T13:30');
+example('2014-02/2014-04');
+example('2014-02--2014-04');
+example('2014-02/04');
+example('2014-02-03/05');
+example('2014-02-03T22:00/22:15');
+example('2014-02-03T22:00/15');
+example('2014-03/');
+example('/2014-03');
+example('2014-03/P1W');
+example('P1W/2014-05-25T23:59:59');
+example('P1Y/');
+example('P1Y');
+example('P2M/');
+example('P3W/');
+example('P4D/');
+example('PT5H/');
+example('PT6M/');
+example('PT7S/');
+example('P1DT1H/');
+
+function example($dateInterval) {
+ $dateIntervalArray = parseDateInterval($dateInterval);
+ echo $dateInterval, "\t=>\t",
+ $dateIntervalArray[0] == null ? 'null' : @date('c', $dateIntervalArray[0]), '/',
+ $dateIntervalArray[1] == null ? 'null' : @date('c', $dateIntervalArray[1]), "\n";
+}
+*/
+
+function _dateFloor($isoDate) {
+ $x = explode('T', $isoDate, 2);
+ $t = isset($x[1]) ? str_pad($x[1], 6, '0') : '000000';
+ return str_pad($x[0], 8, '01') . 'T' . $t;
+}
+
+function _dateCeiling($isoDate) {
+ $x = explode('T', $isoDate, 2);
+ $t = isset($x[1]) && strlen($x[1]) > 1 ? str_pad($x[1], 6, '59') : '235959';
+ switch (strlen($x[0])) {
+ case 4:
+ return $x[0] . '1231T' . $t;
+ case 6:
+ $d = @strtotime($x[0] . '01');
+ return $x[0] . date('t', $d) . 'T' . $t;
+ default:
+ return $x[0] . 'T' . $t;
+ }
+}
+
+function _noDelimit($isoDate) {
+ return $isoDate === null || $isoDate === '' ? null :
+ str_replace(array('-', ':'), '', $isoDate); //FIXME: Bug with negative time zone
+}
+
+function _dateRelative($d1, $d2) {
+ if ($d2 === null) {
+ return $d1 !== null && $d1[0] !== 'P' ? $d1 : null;
+ } elseif ($d2 !== '' && $d2[0] != 'P' && $d1 !== null && $d1[0] !== 'P') {
+ $y2 = substr($d2, 0, 4);
+ if (strlen($y2) < 4 || !ctype_digit($y2)) { //Does not start by a year
+ $d2 = _noDelimit($d2);
+ return substr($d1, 0, -strlen($d2)) . $d2; //Add prefix from $d1
+ }
+ }
+ return _noDelimit($d2);
+}
+
+/**
+ * Parameter $dateInterval is a string containing an ISO 8601 time intervals.
+ * Returns an array with the minimum and maximum Unix timestamp of this interval, or null if open interval.
+ */
+function parseDateInterval($dateInterval) {
+ $dateInterval = trim($dateInterval);
+ $dateInterval = str_replace('--', '/', $dateInterval);
+ $dateInterval = strtoupper($dateInterval);
+ $min = null;
+ $max = null;
+ $x = explode('/', $dateInterval, 2);
+ $d1 = _noDelimit($x[0]);
+ $d2 = _dateRelative($d1, count($x) > 1 ? $x[1] : null);
+ if ($d1 !== null && $d1[0] !== 'P') {
+ $min = @strtotime(_dateFloor($d1));
+ }
+ if ($d2 !== null) {
+ if ($d2[0] === 'P') {
+ try {
+ $di2 = new DateInterval($d2);
+ $dt1 = @date_create(); //new DateTime() would create an Exception if the default time zone is not defined
+ if ($min !== null && $min !== false) {
+ $dt1->setTimestamp($min);
+ }
+ $max = $dt1->add($di2)->getTimestamp() - 1;
+ } catch (Exception $e) {
+ $max = false;
+ }
+ } elseif ($d1 === null || $d1[0] !== 'P') {
+ $max = @strtotime(_dateCeiling($d2));
+ } else {
+ $max = @strtotime($d2);
+ }
+ }
+ if ($d1 !== null && $d1[0] === 'P') {
+ try {
+ $di1 = new DateInterval($d1);
+ $dt2 = @date_create();
+ if ($max !== null && $max !== false) {
+ $dt2->setTimestamp($max);
+ }
+ $min = $dt2->sub($di1)->getTimestamp() + 1;
+ } catch (Exception $e) {
+ $min = false;
+ }
+ }
+ return array($min, $max);
+}