summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2004-07-26 18:42:31 +0000
committerDries Buytaert <dries@buytaert.net>2004-07-26 18:42:31 +0000
commitd21207ae85e8dc27aebb38fc681db85371f429de (patch)
treea034e9962ff22a6f9f6e865ec1033c46885b7a06
parentad5e3ebb75df5c861251ba3ed3dd954a2b2241b4 (diff)
downloadbrdo-d21207ae85e8dc27aebb38fc681db85371f429de.tar.gz
brdo-d21207ae85e8dc27aebb38fc681db85371f429de.tar.bz2
- Patch #8531 by drumm: took this date parser from MagpieRSS (conveniently GPL). The main benefit here is that timezones are handled properly (I have been noticing increasing complaints about that). I tested with a few feeds of different time formats and time zones and everything appeared correctly in my site's local time. Making this another function adds the benefit of parsability by other RSS (or other contexts) and RSS extension handling functions, where the W3C DTF is recomended.
-rw-r--r--modules/aggregator.module63
-rw-r--r--modules/aggregator/aggregator.module63
2 files changed, 92 insertions, 34 deletions
diff --git a/modules/aggregator.module b/modules/aggregator.module
index 91e4514dd..ec0e1a648 100644
--- a/modules/aggregator.module
+++ b/modules/aggregator.module
@@ -394,6 +394,43 @@ function aggregator_refresh($feed) {
}
}
+/**
+ * Parse the W3C date/time format, a subset of ISO 8601. PHP date parsing
+ * functions do not handle this format.
+ * See http://www.w3.org/TR/NOTE-datetime for more information.
+ * Origionally from MagpieRSS (http://magpierss.sourceforge.net/).
+ *
+ * @param $date_str A string with a potentially W3C DTF date.
+ * @return A timestamp if parsed sucessfully or -1 if not.
+ */
+function aggregator_parse_w3cdtf($date_str) {
+ if (preg_match('/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(:(\d{2}))?(?:([-+])(\d{2}):?(\d{2})|(Z))?/', $date_str, $match)) {
+ list($year, $month, $day, $hours, $minutes, $seconds) = array($match[1], $match[2], $match[3], $match[4], $match[5], $match[6]);
+ // calc epoch for current date assuming GMT
+ $epoch = gmmktime($hours, $minutes, $seconds, $month, $day, $year);
+ if ($match[10] != 'Z') { // Z is zulu time, aka GMT
+ list($tz_mod, $tz_hour, $tz_min) = array($match[8], $match[9], $match[10]);
+ // zero out the variables
+ if (!$tz_hour) {
+ $tz_hour = 0;
+ }
+ if (!$tz_min) {
+ $tz_min = 0;
+ }
+ $offset_secs = (($tz_hour * 60) + $tz_min) * 60;
+ // is timezone ahead of GMT? then subtract offset
+ if ($tz_mod == '+') {
+ $offset_secs *= -1;
+ }
+ $epoch += $offset_secs;
+ }
+ return $epoch;
+ }
+ else {
+ return -1;
+ }
+}
+
function aggregator_parse_feed(&$data, $feed) {
global $items, $image, $channel;
@@ -475,20 +512,12 @@ function aggregator_parse_feed(&$data, $feed) {
else if ($item['DCTERMS:MODIFIED']) $date = $item['DCTERMS:MODIFIED']; // Dublin core
else $date = 'now';
- $timestamp = strtotime($date); // strtotime() returns -1 on failure
-
+ $timestamp = strtotime($date); // strtotime() returns -1 on failure
if ($timestamp < 0) {
- /*
- ** The Dublin core's default data format uses ISO 8601 which can't
- ** be parsed directly using PHP's strtotime(). It is not the only
- ** valid format so this might fail nonetheless ...
- */
- list($year, $month, $day, $hour, $minute, $second) = sscanf($date, '%4d-%2d-%2dT%2d:%2d:%2d');
- $timestamp = strtotime("$year-$month-$day $hour:$minute:$second");
- }
-
- if ($timestamp < 0) {
- $timestamp = time();
+ $timestamp = aggregator_parse_w3cdtf($date); // also returns -1 on failure
+ if ($timestamp < 0) {
+ $timestamp = time(); // better than nothing
+ }
}
/*
@@ -533,19 +562,19 @@ function aggregator_parse_feed(&$data, $feed) {
function aggregator_save_item($edit) {
if ($edit['iid'] && $edit['title']) {
- db_query("UPDATE {aggregator_item} SET title = '%s', link = '%s', author = '%s', description = '%s' WHERE iid = %d", $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['iid']);
+ db_query('UPDATE {aggregator_item} SET title = \'%s\', link = \'%s\', author = \'%s\', description = \'%s\' WHERE iid = %d', $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['iid']);
}
else if ($edit['iid']) {
db_query('DELETE FROM {aggregator_item} WHERE iid = %d', $edit['iid']);
db_query('DELETE FROM {aggregator_category_item} WHERE iid = %d', $edit['iid']);
}
else if ($edit['title'] && $edit['link']) {
- $next_id = db_next_id('{aggregator_item}_iid');
- db_query("INSERT INTO {aggregator_item} (iid, fid, title, link, author, description, timestamp) VALUES (%d, %d, '%s', '%s', '%s', '%s', %d)", $next_id, $edit['fid'], $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['timestamp']);
+ $edit['iid'] = db_next_id('{aggregator_item}_iid');
+ db_query('INSERT INTO {aggregator_item} (iid, fid, title, link, author, description, timestamp) VALUES (%d, %d, \'%s\', \'%s\', \'%s\', \'%s\', %d)', $edit['iid'], $edit['fid'], $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['timestamp']);
// file the items in the categories indicated by the feed
$categories = db_query('SELECT cid FROM {aggregator_category_feed} WHERE fid = %d', $edit['fid']);
while ($category = db_fetch_object($categories)) {
- db_query('INSERT INTO {aggregator_category_item} (cid, iid) VALUES (%d, %d)', $category->cid, $next_id);
+ db_query('INSERT INTO {aggregator_category_item} (cid, iid) VALUES (%d, %d)', $category->cid, $edit['iid']);
}
}
}
diff --git a/modules/aggregator/aggregator.module b/modules/aggregator/aggregator.module
index 91e4514dd..ec0e1a648 100644
--- a/modules/aggregator/aggregator.module
+++ b/modules/aggregator/aggregator.module
@@ -394,6 +394,43 @@ function aggregator_refresh($feed) {
}
}
+/**
+ * Parse the W3C date/time format, a subset of ISO 8601. PHP date parsing
+ * functions do not handle this format.
+ * See http://www.w3.org/TR/NOTE-datetime for more information.
+ * Origionally from MagpieRSS (http://magpierss.sourceforge.net/).
+ *
+ * @param $date_str A string with a potentially W3C DTF date.
+ * @return A timestamp if parsed sucessfully or -1 if not.
+ */
+function aggregator_parse_w3cdtf($date_str) {
+ if (preg_match('/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(:(\d{2}))?(?:([-+])(\d{2}):?(\d{2})|(Z))?/', $date_str, $match)) {
+ list($year, $month, $day, $hours, $minutes, $seconds) = array($match[1], $match[2], $match[3], $match[4], $match[5], $match[6]);
+ // calc epoch for current date assuming GMT
+ $epoch = gmmktime($hours, $minutes, $seconds, $month, $day, $year);
+ if ($match[10] != 'Z') { // Z is zulu time, aka GMT
+ list($tz_mod, $tz_hour, $tz_min) = array($match[8], $match[9], $match[10]);
+ // zero out the variables
+ if (!$tz_hour) {
+ $tz_hour = 0;
+ }
+ if (!$tz_min) {
+ $tz_min = 0;
+ }
+ $offset_secs = (($tz_hour * 60) + $tz_min) * 60;
+ // is timezone ahead of GMT? then subtract offset
+ if ($tz_mod == '+') {
+ $offset_secs *= -1;
+ }
+ $epoch += $offset_secs;
+ }
+ return $epoch;
+ }
+ else {
+ return -1;
+ }
+}
+
function aggregator_parse_feed(&$data, $feed) {
global $items, $image, $channel;
@@ -475,20 +512,12 @@ function aggregator_parse_feed(&$data, $feed) {
else if ($item['DCTERMS:MODIFIED']) $date = $item['DCTERMS:MODIFIED']; // Dublin core
else $date = 'now';
- $timestamp = strtotime($date); // strtotime() returns -1 on failure
-
+ $timestamp = strtotime($date); // strtotime() returns -1 on failure
if ($timestamp < 0) {
- /*
- ** The Dublin core's default data format uses ISO 8601 which can't
- ** be parsed directly using PHP's strtotime(). It is not the only
- ** valid format so this might fail nonetheless ...
- */
- list($year, $month, $day, $hour, $minute, $second) = sscanf($date, '%4d-%2d-%2dT%2d:%2d:%2d');
- $timestamp = strtotime("$year-$month-$day $hour:$minute:$second");
- }
-
- if ($timestamp < 0) {
- $timestamp = time();
+ $timestamp = aggregator_parse_w3cdtf($date); // also returns -1 on failure
+ if ($timestamp < 0) {
+ $timestamp = time(); // better than nothing
+ }
}
/*
@@ -533,19 +562,19 @@ function aggregator_parse_feed(&$data, $feed) {
function aggregator_save_item($edit) {
if ($edit['iid'] && $edit['title']) {
- db_query("UPDATE {aggregator_item} SET title = '%s', link = '%s', author = '%s', description = '%s' WHERE iid = %d", $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['iid']);
+ db_query('UPDATE {aggregator_item} SET title = \'%s\', link = \'%s\', author = \'%s\', description = \'%s\' WHERE iid = %d', $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['iid']);
}
else if ($edit['iid']) {
db_query('DELETE FROM {aggregator_item} WHERE iid = %d', $edit['iid']);
db_query('DELETE FROM {aggregator_category_item} WHERE iid = %d', $edit['iid']);
}
else if ($edit['title'] && $edit['link']) {
- $next_id = db_next_id('{aggregator_item}_iid');
- db_query("INSERT INTO {aggregator_item} (iid, fid, title, link, author, description, timestamp) VALUES (%d, %d, '%s', '%s', '%s', '%s', %d)", $next_id, $edit['fid'], $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['timestamp']);
+ $edit['iid'] = db_next_id('{aggregator_item}_iid');
+ db_query('INSERT INTO {aggregator_item} (iid, fid, title, link, author, description, timestamp) VALUES (%d, %d, \'%s\', \'%s\', \'%s\', \'%s\', %d)', $edit['iid'], $edit['fid'], $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['timestamp']);
// file the items in the categories indicated by the feed
$categories = db_query('SELECT cid FROM {aggregator_category_feed} WHERE fid = %d', $edit['fid']);
while ($category = db_fetch_object($categories)) {
- db_query('INSERT INTO {aggregator_category_item} (cid, iid) VALUES (%d, %d)', $category->cid, $next_id);
+ db_query('INSERT INTO {aggregator_category_item} (cid, iid) VALUES (%d, %d)', $category->cid, $edit['iid']);
}
}
}