跳转到内容

XQuery/Net 工作日

来自维基教科书,自由的教科书

为了计算许多文档的“有效”年龄,您需要计算它们在各个阶段的实际工作天数。这意味着您需要计算工作日,但不包括周末。您甚至可以排除节假日,以便生成一致的陈旧报告。

由于 NetWorkingDays 是许多系统共用的计算,因此使用 XQuery 模块来存放逻辑是合理的。

module namespace fxx = "http://xquery.wikibooks.org/fxx";

declare function fxx:net-working-days-n($s as xs:date, $f as xs:date, $dates as xs:date*, $total as xs:integer) as xs:integer {
    if ($s= $f)
    then $total
    else if (fxx:weekday($s) and not($s = $dates))
             then fxx:net-working-days-n($s + xs:dayTimeDuration('P1D'), $f, $dates,$total + 1)
             else fxx:net-working-days-n($s + xs:dayTimeDuration('P1D'), $f, $dates,$total )
};

declare function fxx:net-working-days($s as xs:date, $f as xs:date) as xs:integer {

(:  this function returns one less than the number returned from Excel NETWORKDAY :
    networkdays($d,$d) should be 0 but it is 1.
    networkdays and workday should be inverses and they are not
    common practice seems to be to subtract one anyway.
  :)
  (:  assumes  $s <= $f :)
    fxx:net-working-days-n($s,$f, (), 0)

};

declare function fxx:net-working-days($s as xs:date,$f as xs:date, $dates as xs:date*) as xs:integer {
    fxx:net-working-days-n($s,$f, $dates, 0)

};

此计算的核心是一个 NetWorkingDays 算法,它接受两个日期作为参数。

示例测试驱动程序

[编辑 | 编辑源代码]
xquery version "1.0";

import module namespace fxx = "http://xquery.wikibook.org/fxx" at "net-working-days.xq";

(: Test driver for Net Working Days
 : tags to generate documentation using xqdoc.org scripts at http://www.xqdoc.org/qs_exist.html
 :
 : @return XHTML table for next "caldays" days from now including working days calculations from today
 : @input-parameter: caldays - an integer number of calendar days in the future from now
 :
 :)
 
let $cal-days := xs:integer(request:get-parameter("caldays", "30"))

let $now := xs:date(substring(current-date(),1,10))
return
<html>
   <body>
      <h1>Days from {$now}</h1>
      <p>Today is a {fxx:day-of-week-name-en(xs:date(substring(current-date(),1,10)))}</p>
      <p>Format: net-working-days.xq?cal-days=50</p>
      <table border="1">
      <thead>
          <tr>
              <th>Cal Days</th>
              <th>Future Date</th>
              <th>Day of Week</th>
              <th>Net Working Days</th>
          </tr>
      </thead>
      {
      for $i in (0 to $cal-days)
         let $d :=  $now + xs:dayTimeDuration(concat('P',$i,'D'))
         let $dow := fxx:day-of-week($d)
         return
         <tr>
            <td align="center">{$i}</td>
            <td align="center">{$d}</td>
            <td align="center">{fxx:day-of-week-name-en(xs:date(substring($d,1,10)))}</td>
            <td align="center">{fxx:net-working-days(xs:date(substring(current-date(),1,10)),$d)}</td>
      </tr>
      }
      </table>
   <br/>
   <a href="index.xhtml">Back to Unit Testing Main Menu</a>
   <br/>
   <a href="../../index.xhtml">Back to CRV Main Menu</a>
   </body>
</html>

递归函数有效,但速度很慢。它必须对两个日期之间的每个日期调用自身一次。另一种方法是计算每个星期部分的结束天数,计算周数并乘以 5。

代码??

该内容最初由 Chris Wallace 提供。

华夏公益教科书