]> Creatis software - CreaPhase.git/blobdiff - octave_packages/financial-0.4.0/nweekdate.m
Add a useful package (from Source forge) for octave
[CreaPhase.git] / octave_packages / financial-0.4.0 / nweekdate.m
diff --git a/octave_packages/financial-0.4.0/nweekdate.m b/octave_packages/financial-0.4.0/nweekdate.m
new file mode 100644 (file)
index 0000000..28b86ed
--- /dev/null
@@ -0,0 +1,152 @@
+## Copyright (C) 2008 Bill Denney <bill@denney.ws>
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 3 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {last =} nweekdate (n, weekday, year, month, nextday)
+##
+## Returns the @var{n}th occurrence of @var{weekday} from the
+## @var{month} and @var{year}.  If the optional @var{nextday} argument
+## is given, then the week must also contain @var{nextday}.  If @var{n}
+## is greater than the number of occurrences of that day in the month, 0
+## is returned.
+##
+## @seealso{eomdate, lweekdate, weekday}
+## @end deftypefn
+
+function t = nweekdate (varargin)
+  if nargin < 4 || nargin > 5
+       error ("4 or 5 input arguments are required")
+  elseif nargin == 4
+       varargin{5} = 0;
+  endif
+
+  ## special handling so that most of this code will not need to be
+  ## duplicated in lweekdate
+  do_lweekdate = is_lweekdate(varargin{1});
+  if do_lweekdate
+       varargin{1} = 1;
+  endif
+
+  scale = cellfun (@numel, varargin);
+  if ~ all (scale == 1 | scale == max(scale));
+       error("All inputs must be either scalars or have the same number of elements");
+  else
+       ## make sure that the sizes are the same for any non-scalar inputs
+       ind = find (scale > 1);
+       if length(ind) > 1
+         for i = 2:length (ind)
+               if ndims (varargin{ind(1)}) ~= ndims (varargin{ind(i)})
+                 error("Mismatching dimensions on inputs %d and %d", ind(1), ind(i));
+               elseif ~ all (size (varargin{ind(1)}) == size (varargin{ind(i)}))
+                 error("The sizes of inputs %d and %d do not match", ind(1), ind(i));
+               endif
+         endfor
+       endif
+  endif
+
+  if max(scale) > 1
+       t = zeros (size (varargin{ind(1)}));
+       for i = 1:numel (varargin{ind(1)})
+         args = cell(5,1);
+         for j = 1:5
+               if isscalar (varargin{j})
+                 args{j} = varargin{j};
+               else
+                 args{j} = varargin{j}(i);
+               endif
+         endfor
+         if do_lweekdate
+               args{1} = "lweekdate";
+         end
+         t(i) = nweekdate (args{:});
+       endfor
+  else
+       ## Do the real work.
+       n = varargin{1};
+       wd = varargin{2};
+       y = varargin{3};
+       mon = varargin{4};
+       nextday = varargin{5};
+
+       ## Find the day of the week for the last day of the mon.
+       doml = eomday (y, mon);
+       dowl = weekday (datenum (y, mon, doml));
+       ## Make sure that the day is in the weeks for the last then the
+       ## first week.
+       if (wd < nextday) || (dowl < wd)
+         ## adjust the last day
+         adjust = 7;
+       else
+         adjust = 0;
+       endif
+       dom = sort((doml - dowl + wd - adjust):-7:1);
+       if nextday && (dom(1) <= wd - nextday)
+         # adjust the first day
+         dom(1) = [];
+       endif
+       if do_lweekdate
+         t = datenum (y, mon, dom(end));
+    elseif n > length(dom)
+         t = 0;
+       else
+         t = datenum (y, mon, dom(n));
+       end
+  endif
+
+endfunction
+
+function v = is_lweekdate(v)
+  if ischar(v)
+       if strcmp (v, "lweekdate")
+         v = true();
+       else
+         error("Invalid input for n")
+       endif
+  else
+       v = false();
+  endif
+endfunction
+
+# Tests for all calling options
+# Find the first Wednesday in Jan 2008
+%!assert(nweekdate(1, 4, 2008, 1), datenum(2008, 1, 2))
+# Find the second Wednesday in Jan 2008
+%!assert(nweekdate(2, 4, 2008, 1), datenum(2008, 1, 9))
+# Find the third Wednesday in Jan 2008
+%!assert(nweekdate(3, 4, 2008, 1), datenum(2008, 1, 16))
+# Find the fourth Wednesday in Jan 2008
+%!assert(nweekdate(4, 4, 2008, 1), datenum(2008, 1, 23))
+# Find the fifth Wednesday in Jan 2008
+%!assert(nweekdate(5, 4, 2008, 1), datenum(2008, 1, 30))
+# Find the sixth Wednesday in Jan 2008, it doesn't exist, so return 0
+%!assert(nweekdate(6, 4, 2008, 1), 0)
+# Find the fifth Friday in Jan 2008, it doesn't exist, so return 0
+%!assert(nweekdate(5, 6, 2008, 1), 0)
+# Find the first Wednesday in Jan 2008 in the same week as a Monday
+# WARNING: it is unclear from the Matlab docs if this should work or if 
+# this should be called the second Wednesday in Jan 2008.
+%!assert(nweekdate(1, 4, 2008, 1, 2), datenum(2008, 1, 9))
+# Find the fifth Wednesday in Jan 2008 in the same week as a Friday.
+# It doesn't exist, so return 0
+%!assert(nweekdate(5, 4, 2008, 1, 6), 0)
+# Try vector arguments
+%!assert(nweekdate(1:6, 4, 2008, 1, 6), [datenum(2008, 1, 2:7:23), 0, 0])
+
+# Try the lweekdate operation of this function:
+# Find the last Wednesday in Jan 2008
+%!assert(nweekdate('lweekdate', 4, 2008, 1), datenum(2008, 1, 30))
+# Find the last Wednesday in Jan 2008 with a Friday
+%!assert(nweekdate('lweekdate', 4, 2008, 1, 6), datenum(2008, 1, 23))
+