diff --git a/modules/aggregator.module b/modules/aggregator.module
index 91e4514dde71f0d700a6b12f5eee1011dccbcab1..ec0e1a648bad2511ec4f56d76daf4119c1b4a09e 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 91e4514dde71f0d700a6b12f5eee1011dccbcab1..ec0e1a648bad2511ec4f56d76daf4119c1b4a09e 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']);
     }
   }
 }