Как сравнить время GMT и EST из xml с помощью xquery

Я столкнулся с этой проблемой: я получаю RSS-каналы с разных веб-страниц, а затем мне нужно упорядочить их по дате. Я использую xquery для обработки xml и базу данных eXist для хранения rss/xml. Вот мой код:

for $item in subsequence(collection('/db/bla/user/feed')//item[contains(title, $search)], $start, $num)
                 let $title:= $item/title/text()
                 let $desc:= $item/description/text()
                 let $link := $item/link/text()
                 let $date:= $item/pubDate/text()
                 order by $date

это не работает. И я предполагаю, что проблема в разном времени по Гринвичу и восточному поясному времени, поэтому порядок по дате $ не работает должным образом. Пожалуйста, помогите, я застрял здесь.

Заранее спасибо!

ИЗМЕНИТЬ:

Вот формат даты и времени, который я получаю из тега pubDate:

Mon, 10 Dec 2012 13:32:24 EST

or

Mon, 10 Dec 2012 13:32:24 GMT

person user1598696    schedule 10.01.2013    source источник
comment
Похоже, вам нужно будет проанализировать dateTime. Некоторые API имеют встроенные функции этих типов: MarkLogic, Java, .NET и т. д., поэтому вам придется решить, хотите ли вы анализировать свой dateTime вне XQuery или написать его с нуля в XQuery, и в этом случае это должно наверное другой вопрос.   -  person wst    schedule 10.01.2013
comment
какую версию существования вы используете?   -  person Jens Erat    schedule 11.01.2013
comment
@Ranon Я могу использовать версию 3.0 и версию 1.0, потому что обе версии поддерживаются в eXist db версии 2.0, я думаю... теперь я использую 1.0 для своих нужд   -  person user1598696    schedule 11.01.2013
comment
Меня не интересовала ваша версия XQuery, но ваша версия eXist dv; но вы и на это ответили. Смотрите мой ответ ниже. :)   -  person Jens Erat    schedule 11.01.2013


Ответы (3)


Попробуйте указать $date как фактическую дату/время:

let $date:= xs:dateTime($item/pubDate/text())

Если формат даты/времени согласован, вы можете реализовать свой собственный конвертер. Две части, которые доставят вам больше всего проблем, в примере из вашего комментария, это месяц и часовой пояс. Месяц должен быть числовым, и вам нужно будет преобразовать часовой пояс в эквивалентное смещение UTC.

Вот пример:

declare variable $months := ('jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec');
declare variable $timezoneMap := 
    <map>
        <tz>
            <numeric>-05:00</numeric>
            <alpha>est</alpha>
        </tz>
    </map>;

declare function local:formatDate($origdate as xs:string) as xs:dateTime {
    let $dateTokens := tokenize($origdate,' ')  
    let $timezone := $timezoneMap/tz[lower-case($dateTokens[6])=alpha]/numeric/text()
    let $month := string(index-of($months,lower-case($dateTokens[3])))
    let $newDate := concat($dateTokens[4],'-',if (string-length($month)=1) then concat('0',$month) else $month,'-',$dateTokens[2],
                           'T',$dateTokens[5],$timezone)
    return
        xs:dateTime($newDate)
};

Затем вы можете использовать функцию следующим образом:

let $date:= local:formatDate($item/pubDate)

Кроме того, если вы используете XQuery 3.0, вы можете использовать карты. для часового пояса и месяца:

declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
declare variable $months := map{"jan":="01","feb":="02","mar":="03","apr":="04","may":="05","jun":="06",
                                "jul":="07","aug":="08","sep":="09","oct":="10","nov":="11","dec":="12"};
declare variable $timezoneMap := map{"est":="-05:00"};

declare function local:formatDate($origdate as xs:string) as xs:dateTime {
    let $dateTokens := tokenize($origdate,' ')
    let $newDate := concat($dateTokens[4],'-',$months(lower-case($dateTokens[3])),'-',$dateTokens[2],
                           'T',$dateTokens[5],$timezoneMap(lower-case($dateTokens[6])))
    return
        xs:dateTime($newDate)
};
person Daniel Haley    schedule 10.01.2013
comment
Спасибо за помощь. Но это не работает. я получаю это исключение: ‹/exception›‹message›‹path›....‹/path› err: FORG0001: недопустимая лексическая форма для значения, похожего на дату и время «Пн, 10 декабря 2012 г. 13:32:24 EST» Пн, 10 декабря 2012 г. 13:32:24 EST ‹/сообщение› ‹/исключение› - person user1598696; 10.01.2013
comment
Ах, да, это не xs:dateTime. - person Daniel Haley; 10.01.2013
comment
спасибо за ваши усилия, ваше решение выглядит так, как будто оно может работать, но я не знаю, как я могу использовать его в моем случае, см. мое редактирование для типа моего формата даты. Как я могу изменить ваше решение? Спасибо - person user1598696; 11.01.2013
comment
@user1598696 user1598696 - Мое решение работает для обоих примеров времени/даты в вашем редактировании. Единственное отличие состоит в том, что GMT не имеет смещения (чего и не должно быть). Оба возвращают действительные xs:dateTime. Если у вас есть другие часовые пояса или форматы месяца в любом из ваших фидов, вам придется добавить их. (Я могу добавить пример, если это поможет.) - person Daniel Haley; 11.01.2013
comment
Я получаю эту ошибку, когда пробую ваш пример: err:FORG0001: недопустимая лексическая форма для значения, похожего на дату и время '2013-1-09T20:23:05-05:00' 2013-1-09T20:23:05-05 :00 [строка 22, столбец 15] В функции: local:formatDate(xs:string*) [22:15:String] -- В чем проблема? Пожалуйста помоги. Спасибо - person user1598696; 11.01.2013
comment
@ user1598696 - Упс. Это потому, что index-of() возвращает 1 за январь, а не 01. Я сделаю обновление, когда у меня будет минутка. - person Daniel Haley; 11.01.2013
comment
Большое спасибо за помощь! - person user1598696; 11.01.2013

Создание парсера формата даты в XQuery, вероятно, не лучшая идея; вам придется иметь дело со всем этим преобразованием часовых поясов (и, что еще хуже, с переходом на летнее время...) самостоятельно.

Официальный способ: DateTime-Module

БД eXist имеет собственный модуль DateTime на основе java.text.SimpleDateFormat. Модуль должен быть скомпилирован и активирован перед его использованием и не включен в текущую стабильную версию eXists (но в версию для разработчиков 1.4.3 и предварительную версию 2).

Предупреждение: он использует локаль вашей системы по умолчанию, которая в моем случае не была английской (поэтому распознавание дат с треском провалилось).

Если вам удалось включить его (если вы этого не сделали, это, вероятно, еще один вопрос на Администраторе базы данных, родственном сайте SO), вы должны иметь возможность запускать этот код для анализа дат в указанном формате:

import module namespace datetime = "http://exist-db.org/xquery/datetime";
datetime:parse-dateTime('Mon, 10 Dec 2012 13:32:24 GMT', 'EEE, d MMM yyyy HH:mm:ss Z')

Грязный хак: взаимодействие с Java

Если вы используете более старую версию eXist или не можете использовать модуль по другим причинам, вы можете активировать привязки Java в conf.xml и вызвать эту функцию напрямую:

declare namespace sdtf="java:java.text.SimpleDateFormat";
declare namespace date="java:java.util.Date";

(: Parse given date format to java date :)    
let $parse := sdtf:new('EEE, d MMM yyyy HH:mm:ss Z')
(: Output as close to XQuery's xs:dateTime as possible :)
let $format := sdtf:new("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
let $javadate := sdtf:parse($parse, 'Mon, 10 Dec 2012 13:32:24 GMT')
(: Use regex to insert missing ':' and finally cast to xs:dateTime :)
return xs:dateTime(fn:replace(sdtf:format($format, $javadate), '(.*)(\d{2})', '$1:$2'))

Опять же, не забудьте установить язык Java на английский, если он не установлен по умолчанию.

Думаю, это должно работать нормально, по крайней мере, в Saxon (который определил эту привязку java) и BaseX (на самом деле я проверял это здесь).

person Jens Erat    schedule 11.01.2013

Вы можете использовать модуль Date Parser на основе XQuery Райана Гримма. Он создан для MarkLogic, но с небольшими изменениями должен работать и на других системах. См. https://github.com/marklogic/commons/blob/master/dates/date-parser.xqy.

Как указано в комментариях к модулю, поддерживаются следующие форматы даты:

  1. 30 июн 2006 09:39:08 -05:00
  2. 16 апреля 13:49:06 2003 +0200
  3. 04 августа 11:44:58 по восточному поясному времени 2003 г.
  4. 4 января 1998 г., 0:41 по восточному поясному времени
  5. 25 октября 2004 г. 17:06:46 -0500
  6. Пн, 23 сен 0102 23:14:26 +0900
person Joe Wicentowski    schedule 11.01.2013