Есть ли XQuery, эквивалентный оракулу add_months () - PullRequest
0 голосов
/ 12 июня 2019

Функция Oracle (SQL) add_months () добавляет месяц к дате, но также учитывает, относится ли дата к последнему дню месяца, например.ГГГГ-ММ-ДД 2019-02-28 приведет к 2019-05-31 с add_months (3)

https://www.oracletutorial.com/oracle-date-functions/oracle-add_months/

Я перенесу ту же функциональность на xquery иЯ уже узнал о functx:add-months(date, int) и functx:last-day-of-month(date).

Я думаю, я мог бы сделать свою собственную функцию из 2, но здесь работает гораздо больший алгоритм, поэтому я бы предпочел, чтобы эта вещь уже была доступна впроверенная и работающая манера и солидная официальная функция ...

Короче говоря, это было уже подделано в библиотеке функций, о которой я не знаю, или я должен сделать это самостоятельно?

Ответы [ 2 ]

1 голос
/ 12 июня 2019

Оператор «+» позволяет вам добавлять yearMonthDuration к дате. Например

xs:date('2019-02-28') + xs:yearMonthDuration('P3M')

Я не знаю, совпадает ли семантика с функцией Oracle SQL. Они даны на https://www.w3.org/TR/xpath-functions-31/#func-add-dayTimeDuration-to-date

СПУСТЯ

Похоже, что в особых случаях функции Oracle используется последний день месяца, поэтому добавление или вычитание месяцев к дате, являющейся последним днем ​​месяца, дает последний день другого месяца.

Алгоритм W3C (который определяется ссылкой на https://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes) делает это по-другому: он корректирует номера года и месяца (год, месяц, день), и если полученный день выходит за пределы диапазона для Полученный месяц привязывает его к последнему дню этого месяца.

Вы должны быть в состоянии воспроизвести поведение функции Oracle с помощью пользовательской функции. Это может вызвать несколько вспомогательных функций:

function d:is-last-day-of-month($date as xs:date) as xs:boolean {
  month-from-date($date) != month-from-date($date + xs:dayTimeDuration('P1D')
}

function d:last-date-in-month($date as xs:date) as xs:date {
  if (d:is-last-day-of-month($date))
  then $date
  else d:last-date-in-month($date + xs:dayTimeDuration('P1D'))
}

function d:add-months($date as xs:date, $months as xs:integer) {
  if (d:is-last-day-of-month($date))
  then d:last-date-in-month($date + $months * xs:dayTimeDuration('P1M'))
  else $date + $months * xs:dayTimeDuration('P1M')
}
0 голосов
/ 13 июня 2019

Хорошо, я думаю, что я просто решил ее с помощью следующей пользовательской функции, которую я теперь использую в алгоритме вместо официального xquery-> functx: add-months (date, int)

declare function local:addMonths($input as xs:date?, $amount as xs:integer?)
as xs:date?
{
  let $outputN := functx:add-months($input,$amount)
  let $outputLD := functx:last-day-of-month(functx:add-months($input,$amount))
  return if($input = functx:last-day-of-month($input)) then $outputLD else $outputN
};

Требуется дополнительное тестирование, поскольку весь алгоритм, стоящий за этими модификациями, намного сложнее, но первый запуск выглядел отлично

Целью всего алгоритма было изменение атрибутов даты в .xml путем их перемещения, например. дата = "2018-11-28" (обычно) 3 месяца в будущем

Предполагается, что даты должны оставаться относительно источника, что означает перемещение "2018-11-28" 3 месяца вперед должно привести к:

"2019-02-26" (за 2 дня до последнего дня месяца!)

...