]> Creatis software - CreaPhase.git/blob - 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
1 ## Copyright (C) 2008 Bill Denney <bill@denney.ws>
2 ##
3 ## This program is free software; you can redistribute it and/or modify it under
4 ## the terms of the GNU General Public License as published by the Free Software
5 ## Foundation; either version 3 of the License, or (at your option) any later
6 ## version.
7 ##
8 ## This program is distributed in the hope that it will be useful, but WITHOUT
9 ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11 ## details.
12 ##
13 ## You should have received a copy of the GNU General Public License along with
14 ## this program; if not, see <http://www.gnu.org/licenses/>.
15
16 ## -*- texinfo -*-
17 ## @deftypefn {Function File} {last =} nweekdate (n, weekday, year, month, nextday)
18 ##
19 ## Returns the @var{n}th occurrence of @var{weekday} from the
20 ## @var{month} and @var{year}.  If the optional @var{nextday} argument
21 ## is given, then the week must also contain @var{nextday}.  If @var{n}
22 ## is greater than the number of occurrences of that day in the month, 0
23 ## is returned.
24 ##
25 ## @seealso{eomdate, lweekdate, weekday}
26 ## @end deftypefn
27
28 function t = nweekdate (varargin)
29   if nargin < 4 || nargin > 5
30         error ("4 or 5 input arguments are required")
31   elseif nargin == 4
32         varargin{5} = 0;
33   endif
34
35   ## special handling so that most of this code will not need to be
36   ## duplicated in lweekdate
37   do_lweekdate = is_lweekdate(varargin{1});
38   if do_lweekdate
39         varargin{1} = 1;
40   endif
41
42   scale = cellfun (@numel, varargin);
43   if ~ all (scale == 1 | scale == max(scale));
44         error("All inputs must be either scalars or have the same number of elements");
45   else
46         ## make sure that the sizes are the same for any non-scalar inputs
47         ind = find (scale > 1);
48         if length(ind) > 1
49           for i = 2:length (ind)
50                 if ndims (varargin{ind(1)}) ~= ndims (varargin{ind(i)})
51                   error("Mismatching dimensions on inputs %d and %d", ind(1), ind(i));
52                 elseif ~ all (size (varargin{ind(1)}) == size (varargin{ind(i)}))
53                   error("The sizes of inputs %d and %d do not match", ind(1), ind(i));
54                 endif
55           endfor
56         endif
57   endif
58
59   if max(scale) > 1
60         t = zeros (size (varargin{ind(1)}));
61         for i = 1:numel (varargin{ind(1)})
62           args = cell(5,1);
63           for j = 1:5
64                 if isscalar (varargin{j})
65                   args{j} = varargin{j};
66                 else
67                   args{j} = varargin{j}(i);
68                 endif
69           endfor
70           if do_lweekdate
71                 args{1} = "lweekdate";
72           end
73           t(i) = nweekdate (args{:});
74         endfor
75   else
76         ## Do the real work.
77         n = varargin{1};
78         wd = varargin{2};
79         y = varargin{3};
80         mon = varargin{4};
81         nextday = varargin{5};
82
83         ## Find the day of the week for the last day of the mon.
84         doml = eomday (y, mon);
85         dowl = weekday (datenum (y, mon, doml));
86         ## Make sure that the day is in the weeks for the last then the
87         ## first week.
88         if (wd < nextday) || (dowl < wd)
89           ## adjust the last day
90           adjust = 7;
91         else
92           adjust = 0;
93         endif
94         dom = sort((doml - dowl + wd - adjust):-7:1);
95         if nextday && (dom(1) <= wd - nextday)
96           # adjust the first day
97           dom(1) = [];
98         endif
99         if do_lweekdate
100           t = datenum (y, mon, dom(end));
101     elseif n > length(dom)
102           t = 0;
103         else
104           t = datenum (y, mon, dom(n));
105         end
106   endif
107
108 endfunction
109
110 function v = is_lweekdate(v)
111   if ischar(v)
112         if strcmp (v, "lweekdate")
113           v = true();
114         else
115           error("Invalid input for n")
116         endif
117   else
118         v = false();
119   endif
120 endfunction
121
122 # Tests for all calling options
123 # Find the first Wednesday in Jan 2008
124 %!assert(nweekdate(1, 4, 2008, 1), datenum(2008, 1, 2))
125 # Find the second Wednesday in Jan 2008
126 %!assert(nweekdate(2, 4, 2008, 1), datenum(2008, 1, 9))
127 # Find the third Wednesday in Jan 2008
128 %!assert(nweekdate(3, 4, 2008, 1), datenum(2008, 1, 16))
129 # Find the fourth Wednesday in Jan 2008
130 %!assert(nweekdate(4, 4, 2008, 1), datenum(2008, 1, 23))
131 # Find the fifth Wednesday in Jan 2008
132 %!assert(nweekdate(5, 4, 2008, 1), datenum(2008, 1, 30))
133 # Find the sixth Wednesday in Jan 2008, it doesn't exist, so return 0
134 %!assert(nweekdate(6, 4, 2008, 1), 0)
135 # Find the fifth Friday in Jan 2008, it doesn't exist, so return 0
136 %!assert(nweekdate(5, 6, 2008, 1), 0)
137 # Find the first Wednesday in Jan 2008 in the same week as a Monday
138 # WARNING: it is unclear from the Matlab docs if this should work or if 
139 # this should be called the second Wednesday in Jan 2008.
140 %!assert(nweekdate(1, 4, 2008, 1, 2), datenum(2008, 1, 9))
141 # Find the fifth Wednesday in Jan 2008 in the same week as a Friday.
142 # It doesn't exist, so return 0
143 %!assert(nweekdate(5, 4, 2008, 1, 6), 0)
144 # Try vector arguments
145 %!assert(nweekdate(1:6, 4, 2008, 1, 6), [datenum(2008, 1, 2:7:23), 0, 0])
146
147 # Try the lweekdate operation of this function:
148 # Find the last Wednesday in Jan 2008
149 %!assert(nweekdate('lweekdate', 4, 2008, 1), datenum(2008, 1, 30))
150 # Find the last Wednesday in Jan 2008 with a Friday
151 %!assert(nweekdate('lweekdate', 4, 2008, 1, 6), datenum(2008, 1, 23))
152