diff --git a/src/@dates/append_.m b/src/@dates/append_.m index ba5b03eaecd8b0e96a0ce336525d06e6bf6a6c19..398f0325899c65b2794e084c7eb57df055972763 100644 --- a/src/@dates/append_.m +++ b/src/@dates/append_.m @@ -228,4 +228,28 @@ catch end T = all(t); -%@eof:8 \ No newline at end of file +%@eof:8 + +%@test:9 +% Define some dates +B1 = '2020W1'; +B2 = '2020W2'; +B3 = '2020W3'; +B4 = '2020W4'; + +% Call the tested routine. +try + d1 = dates(B1,B2,B3); + d2 = dates(B4); + d1.append_(d2); + t(1) = true; +catch + t(1) = false; +end + +if t(1) + t(2) = isequal(d1, dates(B1, B2, B3, B4)); +end + +T = all(t); +%@eof:9 \ No newline at end of file diff --git a/src/@dates/char.m b/src/@dates/char.m index 864df76b50b13a5b9b9355920157a7fa360dc97d..b68b2e1c3cc9e78422e4784ea98fbd71fb1d1a12 100644 --- a/src/@dates/char.m +++ b/src/@dates/char.m @@ -8,7 +8,7 @@ function s = char(o) % --*-- Unitary tests --*-- % OUTPUTS % - s [string] -% Copyright © 2014-2020 Dynare Team +% Copyright © 2014-2021 Dynare Team % % This code is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -119,4 +119,22 @@ if t(1) t(2) = isequal(str,'1950Y'); end T = all(t); -%@eof:5 \ No newline at end of file +%@eof:5 + +%@test:6 +% Define a dates object +o = dates('1950W1'); + +% Call the tested routine. +try + str = char(o); + t(1) = true; +catch + t(1) = false; +end + +if t(1) + t(2) = isequal(str,'1950W1'); +end +T = all(t); +%@eof:6 diff --git a/src/@dates/dates.m b/src/@dates/dates.m index fcc95b6aa783d93de46fb723a59a738dc3eaf39a..ee5d93d49a4c9132782e050aa34beaf9f560b37b 100644 --- a/src/@dates/dates.m +++ b/src/@dates/dates.m @@ -66,10 +66,23 @@ methods end if (isnumeric(varargin{2}) && isvector(varargin{2}) && all(isint(varargin{2}))) if isnumeric(varargin{3}) && isvector(varargin{3}) && all(isint(varargin{3})) - if all(varargin{3}>=1) && all(varargin{3}<=o.freq) - o.time = varargin{2}(:)*o.freq+varargin{3}(:); + if o.freq==52 + if all(varargin{3}>=1) + if any(islongyear(varargin{2}(:))) && any(varargin{3}(islongyear(varargin{2}(:)))>53) + error('dates:ArgCheck', 'Third input specifies non existing ISO weeks (argument cannot be greater than 53).') + end + if any(~islongyear(varargin{2}(:))) && any(varargin{3}(~islongyear(varargin{2}(:)))>52) + error('dates:ArgCheck', 'Third input specifies non existing ISO weeks (argument cannot be greater than 52 except in long years).') + end + else + error('dates:ArgCheck', 'Third input must contain strictly positive integers.') + end else - error('dates:ArgCheck', 'Third input must contain integers between 1 and %i.', o.freq) + if all(varargin{3}>=1) && all(varargin{3}<=o.freq) + o.time = varargin{2}(:)*o.freq+varargin{3}(:); + else + error('dates:ArgCheck', 'Third input must contain integers between 1 and %i.', o.freq) + end end else error('dates:ArgCheck', 'Third input must be a vector of integers.') diff --git a/src/@dates/double.m b/src/@dates/double.m index 1470c5c754aa465c7a7ab31896b8a675e0499016..8a96eed5519352041afb4b8decf9fa3758c61fee 100644 --- a/src/@dates/double.m +++ b/src/@dates/double.m @@ -28,9 +28,9 @@ function [m, f] = double(o) % --*-- Unitary tests --*-- % You should have received a copy of the GNU General Public License % along with Dynare. If not, see <https://www.gnu.org/licenses/>. -if o.freq==365 +if o.freq==365 || o.freq==52 error('This method is not implemented for daily frequency.') - % Would need to find a way to deal with leap years + % Would need to find a way to deal with leap years and long years. end if o.freq == 1 diff --git a/src/utilities/convert/date2string.m b/src/utilities/convert/date2string.m index 623b28e89cfe5e9d397107ddf84d3e725308adce..47a40e25709c40355d1ed5f7f6bb424ef100d9cb 100644 --- a/src/utilities/convert/date2string.m +++ b/src/utilities/convert/date2string.m @@ -27,6 +27,8 @@ function s = date2string(varargin) % --*-- Unitary tests --*-- % You should have received a copy of the GNU General Public License % along with Dynare. If not, see <https://www.gnu.org/licenses/>. +Eschaton = 10000; % End time + if isequal(nargin, 1) if ~(isa(varargin{1}, 'dates') && isequal(length(varargin{1}), 1)) error(['dates::format: Input argument ' inputname(1) ' has to be a dates object with one element!']) @@ -37,7 +39,7 @@ if isequal(nargin, 1) end if isequal(nargin, 2) - if ~isscalar(varargin{2}) || ~isint(varargin{2}) || ~ismember(varargin{2}, [1 2 4 12 365]) + if ~isscalar(varargin{2}) || ~isint(varargin{2}) || ~ismember(varargin{2}, [1 2 4 12 52 365]) error('Second input argument must be an integer scalar equal to 1, 2, 4, 12, or 365 (frequency).') end freq = varargin{2}; @@ -51,6 +53,22 @@ if freq==365 s = datestr(time(1), 'yyyy-mm-dd'); elseif freq==1 s = sprintf('%iY', time); +elseif freq==52 + t0 = cumsum(transpose(islongyear(0:Eschaton))+52); + t1 = find(t0<=time, true, 'last'); + if isempty(t1) + year = 0; + subperiod = time; + else + if time==t0(t1) + year = t1-1; + subperiod = 52+islongyear(year); + else + year = t1; + subperiod = time-t0(t1); + end + end + s = sprintf('%iW%i', year, subperiod); else year = floor((time-1)/freq); subperiod = time-year*freq; diff --git a/src/utilities/convert/freq2string.m b/src/utilities/convert/freq2string.m index a3b90f0dc35e646d91bcbbd2698ed886237dc41e..249abded5e2c253c6541aca237612ab22989e76d 100644 --- a/src/utilities/convert/freq2string.m +++ b/src/utilities/convert/freq2string.m @@ -1,10 +1,10 @@ function s = freq2string(freq) % --*-- Unitary tests --*-- % INPUTS -% - freq [integer] scalar equal to 1, 2, 4, 12, or 365 (resp. annual, bi-annual, quaterly, monthly, or daily) +% - freq [integer] scalar equal to 1, 2, 4, 12, 52, or 365 (resp. annual, bi-annual, quaterly, monthly, weekly, or daily) % % OUTPUTS -% - s [char] scalar equal to Y, S, Q, M, or D (resp. annual, bi-annual, quaterly, monthly, or daily) +% - s [char] scalar equal to Y, S, Q, M, W, or D (resp. annual, bi-annual, quaterly, monthly, weekly, or daily) % Copyright © 2013-2021 Dynare Team % @@ -32,6 +32,8 @@ switch freq s = 'Q'; case 12 s = 'M'; + case 52 + s = 'W'; case 365 s = 'D'; otherwise @@ -46,6 +48,7 @@ try strH = freq2string(2); strQ = freq2string(4); strM = freq2string(12); + strW = freq2string(52); strD = freq2string(365); t(1) = true; catch @@ -57,6 +60,7 @@ if t(1) t(3) = isequal(strH, 'S'); t(4) = isequal(strQ, 'Q'); t(5) = isequal(strM, 'M'); + t(6) = isequal(strW, 'W'); t(6) = isequal(strD, 'D'); end diff --git a/src/utilities/convert/string2date.m b/src/utilities/convert/string2date.m index 718397bd56bd7791f507d131ee54c2d82a45005a..c3ce5deb03af63bbf490f03d5d9dbded4e6cbd5a 100644 --- a/src/utilities/convert/string2date.m +++ b/src/utilities/convert/string2date.m @@ -51,6 +51,13 @@ if ismonthly(a) return end +if isweekly(a) + period = cellfun(@str2double, strsplit(a, {'W','w'})); + date.freq = 52; + date.time = weeksince(period(1), period(2)); + return +end + if isdaily(a) date.freq = 365; date.time(1) = datenum(a, 'yyyy-mm-dd'); diff --git a/src/utilities/is/isdate.m b/src/utilities/is/isdate.m index 673a1bcc42f835fa7b3aae2f7da702731de5dea3..41ba5e9e3412c37d1350b71a851b502809be21f0 100644 --- a/src/utilities/is/isdate.m +++ b/src/utilities/is/isdate.m @@ -8,7 +8,7 @@ function b = isdate(str) % --*-- Unitary tests --*-- % OUTPUTS % - b [logical] scalar equal to true iff str can be interpreted as a date. -% Copyright © 2013-2020 Dynare Team +% Copyright © 2013-2021 Dynare Team % % This file is part of Dynare. % @@ -43,18 +43,20 @@ date_5 = ' 1950'; date_6 = '1950Y'; date_7 = '-1950a'; date_8 = '1950m '; -date_9 = '2000-01-01'; -date_10 = '2000-02-30'; +date_9 = '1950w50'; +date_10 = '2000-01-01'; +date_11 = '2000-02-30'; -t(1) = isequal(isdate(date_1), true); -t(2) = isequal(isdate(date_2), true); -t(3) = isequal(isdate(date_3), true); -t(4) = isequal(isdate(date_4), false); -t(5) = isequal(isdate(date_5), false); -t(6) = isequal(isdate(date_6), true); -t(7) = isequal(isdate(date_7), true); -t(8) = isequal(isdate(date_8), false); -t(9) = isequal(isdate(date_9), true); -t(10) = isequal(isdate(date_10), false); +t(1) = isdate(date_1); +t(2) = isdate(date_2); +t(3) = isdate(date_3); +t(4) = ~isdate(date_4); +t(5) = ~isdate(date_5); +t(6) = isdate(date_6); +t(7) = isdate(date_7); +t(8) = ~isdate(date_8); +t(9) = isdate(date_9); +t(10) = isdate(date_10); +t(11) = ~isdate(date_11); T = all(t); %@eof:1 \ No newline at end of file diff --git a/src/utilities/is/isdates.m b/src/utilities/is/isdates.m index 005156aa70320fddc511a3f8f28c7ec37422ae12..e781dddae4579a383e502436fcd7fb8f7315a577 100644 --- a/src/utilities/is/isdates.m +++ b/src/utilities/is/isdates.m @@ -96,4 +96,19 @@ if t(1) end T = all(t); -%@eof:5 \ No newline at end of file +%@eof:5 + +%@test:6 +try + boolean = isdates('1938W11'); + t(1) = true; +catch + t(1) = false; +end + +if t(1) + t(2) = dassert(boolean, false); +end + +T = all(t); +%@eof:6 \ No newline at end of file diff --git a/src/utilities/is/isfreq.m b/src/utilities/is/isfreq.m index 6344945c3cfba49cfd20a65dfafae00172423ac9..af117ad859c327853aa151940c772bd961082fe4 100644 --- a/src/utilities/is/isfreq.m +++ b/src/utilities/is/isfreq.m @@ -8,7 +8,7 @@ function B = isfreq(A) % --*-- Unitary tests --*-- % OUTPUTS % - B [logical] scalar equal to true iff A can be interpreted as a frequency. -% Copyright © 2013-2020 Dynare Team +% Copyright © 2013-2021 Dynare Team % % This file is part of Dynare. % @@ -28,7 +28,7 @@ function B = isfreq(A) % --*-- Unitary tests --*-- B = false; if ischar(A) - if isequal(length(A),1) && ismember(upper(A),{'Y','A', 'H', 'Q', 'M', 'D'}) + if isequal(length(A),1) && ismember(upper(A),{'Y','A', 'H', 'Q', 'M', 'W', 'D'}) B = true; return end @@ -113,4 +113,19 @@ if t(1) end T = all(t); -%@eof:5 \ No newline at end of file +%@eof:5 + +%@test:6 +try + b = isfreq('W') && isfreq(52); + t(1) = true; +catch + t(1) = false; +end + +if t(1) + t(2) = b; +end + +T = all(t); +%@eof:6 \ No newline at end of file diff --git a/src/utilities/is/isleapyear.m b/src/utilities/is/isleapyear.m index 0a51259dc315f8015eac9a0c1fd7c9dca35bdbcc..ae3a984ad5194faac7fc536438cca39a6cdbfc82 100644 --- a/src/utilities/is/isleapyear.m +++ b/src/utilities/is/isleapyear.m @@ -26,6 +26,11 @@ function b = isleapyear(y) % --*-- Unitary tests --*-- % You should have received a copy of the GNU General Public License % along with Dynare. If not, see <https://www.gnu.org/licenses/>. +if isempty(y) + b = false; + return +end + if isnumeric(y) && isvector(y) && all(isint(y)) b = mod(y,4)==0 & ( mod(y, 100)~=0 | mod(y, 400)==0 ); else diff --git a/src/utilities/is/islongyear.m b/src/utilities/is/islongyear.m new file mode 100644 index 0000000000000000000000000000000000000000..22de544ea41a1fe3f37b46633548ac42e677ccde --- /dev/null +++ b/src/utilities/is/islongyear.m @@ -0,0 +1,72 @@ +function b = islongyear(y) % --*-- Unitary tests --*-- + +% Returns true iff y is a year with 53 weeks. +% +% INPUTS +% - y [integer] scalar or vector, year(s). +% +% OUTPUTS +% - b [logical] scalar or vector, equal to true iff y is a leap year. + + +% Copyright © 2021 Dynare Team +% +% This file is part of Dynare. +% +% Dynare 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. +% +% Dynare 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 Dynare. If not, see <https://www.gnu.org/licenses/>. + +b = mod(y+fix(y/4)-fix(y/100)+fix(y/400),7)==4 | mod(y-1+fix((y-1)/4)-fix((y-1)/100)+fix((y-1)/400),7)==3; + +return + +%@test:1 +Years = [4; 9 ; 15 ; 20 ; 26 ; 32 ; 37 ; 43 ; 48 ; 54 ; 60 ; 65 ; 71 ; 76 ; 82 ; 88 ; 93 ; 99 ; + 105 ; 111 ; 116 ; 122 ; 128 ; 133 ; 139 ; 144 ; 150 ; 156 ; 161 ; 167 ; 172 ; 178 ; 184 ; 189 ; 195 ; + 201 ; 207 ; 212 ; 218 ; 224 ; 229 ; 235 ; 240 ; 246 ; 252 ; 257 ; 263 ; 268 ; 274 ; 280 ; 285 ; 291 ; 296 ; + 303 ; 308 ; 314 ; 320 ; 325 ; 331 ; 336 ; 342 ; 348 ; 353 ; 359 ; 364 ; 370 ; 376 ; 381 ; 387 ; 392 ; 398]; +try + ly = islongyear(Years); + t(1) = true; +catch + t(1) = false; +end + +if t(1) + t(2) = all(ly); +end + +T = all(t); +%@eof:1 + +%@test:2 +LongYears = [4; 9 ; 15 ; 20 ; 26 ; 32 ; 37 ; 43 ; 48 ; 54 ; 60 ; 65 ; 71 ; 76 ; 82 ; 88 ; 93 ; 99 ; + 105 ; 111 ; 116 ; 122 ; 128 ; 133 ; 139 ; 144 ; 150 ; 156 ; 161 ; 167 ; 172 ; 178 ; 184 ; 189 ; 195 ; + 201 ; 207 ; 212 ; 218 ; 224 ; 229 ; 235 ; 240 ; 246 ; 252 ; 257 ; 263 ; 268 ; 274 ; 280 ; 285 ; 291 ; 296 ; + 303 ; 308 ; 314 ; 320 ; 325 ; 331 ; 336 ; 342 ; 348 ; 353 ; 359 ; 364 ; 370 ; 376 ; 381 ; 387 ; 392 ; 398]; + +Years = setdiff(1:400, LongYears); + +try + ly = islongyear(Years); + t(1) = true; +catch + t(1) = false; +end + +if t(1) + t(2) = all(~ly); +end + +T = all(t); +%@eof:2 \ No newline at end of file diff --git a/src/utilities/is/isstringdate.m b/src/utilities/is/isstringdate.m index 9f780d4e147e155b45e908f8dfc4a876eef92ea0..d025b2f285709c71cea8d6d217213ef733bf9ff6 100644 --- a/src/utilities/is/isstringdate.m +++ b/src/utilities/is/isstringdate.m @@ -8,7 +8,7 @@ function b = isstringdate(str) % --*-- Unitary tests --*-- % OUTPUTS % o b integer scalar, equal to 1 if str can be interpreted as a date or 0 otherwise. -% Copyright (C) 2013-2020 Dynare Team +% Copyright (C) 2013-2021 Dynare Team % % This file is part of Dynare. % @@ -26,7 +26,7 @@ function b = isstringdate(str) % --*-- Unitary tests --*-- % along with Dynare. If not, see <https://www.gnu.org/licenses/>. if ischar(str) - b = isquarterly(str) || isyearly(str) || isbiannual(str) || ismonthly(str) || isdaily(str); + b = isquarterly(str) || isyearly(str) || isbiannual(str) || ismonthly(str) || isweekly(str) || isdaily(str); else b = false; end @@ -53,6 +53,7 @@ date_16 = '1948H1'; date_17 = 'h2'; date_18 = '1948-02-12'; date_19 = '12-30'; +date_20 = '1950W2'; t(1) = isstringdate(date_1); t(2) = isstringdate(date_2); @@ -71,8 +72,9 @@ t(14) = ~isstringdate(date_14); t(15) = ~isstringdate(date_15); t(16) = isstringdate(date_16); t(17) = ~isstringdate(date_17); -t(16) = isstringdate(date_18); -t(17) = ~isstringdate(date_19); +t(18) = isstringdate(date_18); +t(19) = ~isstringdate(date_19); +t(20) = isstringdate(date_20); T = all(t); %@eof:1 \ No newline at end of file diff --git a/src/utilities/is/isweekly.m b/src/utilities/is/isweekly.m new file mode 100644 index 0000000000000000000000000000000000000000..75f31debb3ea7007e6817fc651396cd221a4b99a --- /dev/null +++ b/src/utilities/is/isweekly.m @@ -0,0 +1,74 @@ +function b = isweekly(str) % --*-- Unitary tests --*-- + +% Tests if the input can be interpreted as a monthly date. +% +% INPUTS +% o str string. +% +% OUTPUTS +% o b logical scalar, equal to true if str can be interpreted as a weekly date or false otherwise. + +% Copyright © 2021 Dynare Team +% +% This file is part of Dynare. +% +% Dynare 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. +% +% Dynare 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 Dynare. If not, see <https://www.gnu.org/licenses/>. + +if ischar(str) + if isempty(regexp(str,'^-?[0-9]+[Ww]([1-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-3])$','once')) + b = false; + return + else + b = true; + end +else + b = false; + return +end + +% TODO Also test w.r.t. the number of weeks in a year. +if b + period = cellfun(@str2double, strsplit(str, {'W','w'})); + if isequal(period(2), 0) || period(2)>(52+islongyear(period(1))) + b = false; + end +end + + +return + +%@test:1 +date_1 = '1950M2'; +date_2 = '1950W2'; +date_3 = '-1950w2'; +date_4 = '1950W52'; +date_5 = '1950 azd '; +date_6 = '1950Y'; +date_7 = '1950Q3'; +date_8 = '1950m24'; +date_9 = '2003W53'; +date_10 = '2004W53'; + +t(1) = ~isweekly(date_1); +t(2) = isweekly(date_2); +t(3) = isweekly(date_3); +t(4) = isweekly(date_4); +t(5) = ~isweekly(date_5); +t(6) = ~isweekly(date_6); +t(7) = ~isweekly(date_7); +t(8) = ~isweekly(date_8); +t(9) = ~isweekly(date_9); +t(10) = isweekly(date_10); +T = all(t); +%@eof:1 \ No newline at end of file diff --git a/src/utilities/misc/firstdayofyear.m b/src/utilities/misc/firstdayofyear.m new file mode 100644 index 0000000000000000000000000000000000000000..6eff5b25fc5b2ba8fcfc74d76d013ceb1ad00b51 --- /dev/null +++ b/src/utilities/misc/firstdayofyear.m @@ -0,0 +1,75 @@ +function daycode = firstdayofyear(y) % --*-- Unitary tests --*-- + +% Returns the first day of year y. +% +% INPUTS +% - y [integer] scalar or vector, year(s). +% +% OUTPUTS +% - daycode [integer] scalar or vector. +% +% REMARKS +% Days are encoded as follows: +% +% 1 -> Monday +% 2 -> Tuesday +% 3 -> Wednesday +% 4 -> Thursday +% 5 -> Friday +% 6 -> Saturday +% 7 -> Sunday + +% Copyright © 2021 Dynare Team +% +% This file is part of Dynare. +% +% Dynare 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. +% +% Dynare 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 Dynare. If not, see <https://www.gnu.org/licenses/>. + +daycode = mod(1+5*mod(y-1,4)+4*mod(y-1,100)+6*mod(y-1,400), 7); + +% Monday is the first day of the week acoording to ISO-8607 +id = (daycode==0); +daycode(id) = 7; + +return + +%@test:1 +try + dc = firstdayofyear(2000); + t(1) = true; +catch + t(1) = false; +end + +if t(1) + t(2) = dc==6; +end + +T = all(t); +%@eof:1 + +%@test:2 +try + dc = firstdayofyear([2001;2002]); + t(1) = true; +catch + t(1) = false; +end + +if t(1) + t(2) = isequal(dc, [1;2]); +end + +T = all(t); +%@eof:2 \ No newline at end of file diff --git a/src/utilities/misc/firstweekofyear.m b/src/utilities/misc/firstweekofyear.m new file mode 100644 index 0000000000000000000000000000000000000000..3455144ef2347a641fef96f3b144856bb4ff035b --- /dev/null +++ b/src/utilities/misc/firstweekofyear.m @@ -0,0 +1,91 @@ +function [d, m, y] = firstweekofyear(y) % --*-- Unitary tests --*-- + +% Returns the month and day the first week of the year. +% +% INPUTS +% - y [integer] the year. +% +% OUTPUS +% - y [integer] the year of the first iso-8601 week of year y (may be equal to y-1) +% - m [integer] the month number (1 or 12) +% - d [integer] the day of the month. + +% Copyright © 2021 Dynare Team +% +% This file is part of Dynare. +% +% Dynare 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. +% +% Dynare 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 Dynare. If not, see <https://www.gnu.org/licenses/>. + +d = firstdayofyear(y); + +m = ones(length(d), 1); + +id = d==2 | d==3 | d==4; +if any(id) + % Tuesday, Wednesday, or Thursday + m(id) = 12; + y(id) = y(id)-1; + d(id) = 33-d(id); +end + +id = d==5 | d==6 | d==7; +if any(id) + % Friday, Saturday, or Sunday + d(id) = 9-d(id); +end + +return + +%@test:1 +t = false(2,1); + +try + [d, m, y] = firstweekofyear(1971); + t(1) = true; +catch + t(1) = false; +end + +if t(1) + t(2) = d==4; +end + +T = all(t); +%@eof:1 + + +%@test:2 +t = false(10,1); + +try + [d, m, y] = firstweekofyear([1972;1973;1974]); + t(1) = true; +catch + t(1) = false; +end + +if t(1) + t(2) = d(1)==3; + t(3) = d(2)==1; + t(4) = d(3)==31; + t(5) = m(1)==1; + t(6) = m(2)==1; + t(7) = m(3)==12; + t(8) = y(1)==1972; + t(9) = y(2)==1973; + t(10) = y(3)==1973; +end + +T = all(t); +%@eof:2 \ No newline at end of file diff --git a/src/utilities/misc/longyearsince.m b/src/utilities/misc/longyearsince.m new file mode 100644 index 0000000000000000000000000000000000000000..d305c2340e45c1a2e1795f2f335a2ac758a508fa --- /dev/null +++ b/src/utilities/misc/longyearsince.m @@ -0,0 +1,39 @@ +function n = longyearsince(y, z) + +% Returns the number of long years since base year z. +% +% INPUTS +% - y [integer] scalar or vector, the year. +% - z [integer] scalar, base year (default is 0). +% +% OUTPUTS +% - n [integer] scalar or vector, number of long years. + +% Copyright © 2021 Dynare Team +% +% This file is part of Dynare. +% +% Dynare 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. +% +% Dynare 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 Dynare. If not, see <https://www.gnu.org/licenses/>. + +if nargin<2 + z = 0; % Default value for base year. +end + +n = zeros(length(y), 1); + +for i=1:length(y) + if y(i)>=z + n(i) = sum(islongyear(z:y)); + end +end \ No newline at end of file diff --git a/src/utilities/misc/ordinal.m b/src/utilities/misc/ordinal.m new file mode 100644 index 0000000000000000000000000000000000000000..afc4446f987ca1b5236f525cafae5f86c5e9283a --- /dev/null +++ b/src/utilities/misc/ordinal.m @@ -0,0 +1,55 @@ +function o = ordinalinyear(y, m, d) + +% Returns the ordinal date (day number in current year). +% +% INPUTS +% - y [integer] scalar or vector, the year. +% - m [integer] scalar or vector, the month. +% - d [integer] scalar or vector, the day in a month. +% +% OUTPUS +% - o [integer] scalar or vector, day number in year y. + +% Copyright © 2021 Dynare Team +% +% This file is part of Dynare. +% +% Dynare 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. +% +% Dynare 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 Dynare. If not, see <https://www.gnu.org/licenses/>. + +D = [31; 28; 31; 30; 31; 30; 31; 31; 30; 31; 30]; % Number of days in January, February, ..., November + +if ~(isvector(y) && isvector(m) && isvector(d)) || ~(isint(y) && isint(m) && isint(d)) + error('Arguments must be vectors of integers.') +end + +if ~(length(y)==length(m) && length(y)==length(d)) + error('Arguments must have same lengths.') +end + +o = zeros(length(y), 1); + +for i=1:length(o) + o(i) = d(i) + days(y(i), m(i)); +end + +function d = days(y, m) + if m>1 + d = cumsum(D(1:m-1)); + else + d = 0; + end + if m>2 + d = d + isleapyear(y); + end +end \ No newline at end of file diff --git a/src/utilities/misc/ordinalinisoyear.m b/src/utilities/misc/ordinalinisoyear.m new file mode 100644 index 0000000000000000000000000000000000000000..4f82289fab09d95a5448f718d9d357a2d93c3dde --- /dev/null +++ b/src/utilities/misc/ordinalinisoyear.m @@ -0,0 +1,74 @@ +function o = ordinalinisoyear(y, m, d) + +% Returns the ordinal date (day number in current year). +% +% INPUTS +% - y [integer] scalar or vector, the year. +% - m [integer] scalar or vector, the month. +% - d [integer] scalar or vector, the day in a month. +% +% OUTPUTS +% - o [integer] scalar or vector, day number in year y. +% +% REMARKS +% odinalinyear(2000,1,1) returns 1. + +% Copyright © 2021 Dynare Team +% +% This file is part of Dynare. +% +% Dynare 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. +% +% Dynare 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 Dynare. If not, see <https://www.gnu.org/licenses/>. + +D = [31; 28; 31; 30; 31; 30; 31; 31; 30; 31; 30; 31]; % Number of days in January, February, ..., December (for a non leap year) + +if ~(isvector(y) && isvector(m) && isvector(d)) || ~(isint(y) && isint(m) && isint(d)) + error('Arguments must be vectors of integers.') +end + +if ~(length(y)==length(m) && length(y)==length(d)) + error('Arguments must have same lengths.') +end + +if any(m>12) || any(m<1) + error('Second argument must be an integer between 1 and 12 (month).') +end + +if any(d<1) + error('Third argument must be a positive integer (day).') +end + +id = m==2; % February requires a special treatment. + +if any(d(~id)>D(m(~id))) || any(d(id)>28+isleapyear(y(id))) + error('Dates are wrong (third argument cannot be greater than 28, 29, 30 or 31 depending on the value of the second argument).') +end + +o = zeros(length(y), 1); + +for i=1:length(o) + o(i) = d(i) + days(y(i), m(i)); +end + +function n = days(y, m) + if m>1 + n = sum(D(1:m-1)); + else + n = 0; + end + if m>2 + n = n + isleapyear(y); + end +end + +end \ No newline at end of file diff --git a/src/utilities/misc/ordinalinyear.m b/src/utilities/misc/ordinalinyear.m new file mode 100644 index 0000000000000000000000000000000000000000..44d78b3d941fd0f5cc826a34585cd778c966ef19 --- /dev/null +++ b/src/utilities/misc/ordinalinyear.m @@ -0,0 +1,74 @@ +function o = ordinalinyear(y, m, d) + +% Returns the ordinal date (day number in current year). +% +% INPUTS +% - y [integer] scalar or vector, the year. +% - m [integer] scalar or vector, the month. +% - d [integer] scalar or vector, the day in a month. +% +% OUTPUTS +% - o [integer] scalar or vector, day number in year y. +% +% REMARKS +% odinalinyear(2000,1,1) returns 1. + +% Copyright © 2021 Dynare Team +% +% This file is part of Dynare. +% +% Dynare 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. +% +% Dynare 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 Dynare. If not, see <https://www.gnu.org/licenses/>. + +D = [31; 28; 31; 30; 31; 30; 31; 31; 30; 31; 30; 31]; % Number of days in January, February, ..., December (for a non leap year) + +if ~(isvector(y) && isvector(m) && isvector(d)) || ~(isint(y) && isint(m) && isint(d)) + error('Arguments must be vectors of integers.') +end + +if ~(length(y)==length(m) && length(y)==length(d)) + error('Arguments must have same lengths.') +end + +if any(m>12) || any(m<1) + error('Second argument must be an integer between 1 and 12 (month).') +end + +if any(d<1) + error('Third argument must be a positive integer (day).') +end + +id = m==2; % February requires a special treatment. + +if any(d(~id)>D(m(~id))) || any(d(id)>28+isleapyear(y(id))) + error('Dates are wrong (third argument cannot be greater than 28, 29, 30 or 31 depending on the value of the second argument).') +end + +o = zeros(length(y), 1); + +for i=1:length(o) + o(i) = d(i) + days(y(i), m(i)); +end + +function n = days(y, m) + if m>1 + n = sum(D(1:m-1)); + else + n = 0; + end + if m>2 + n = n + isleapyear(y); + end +end + +end \ No newline at end of file diff --git a/src/utilities/misc/weeksince.m b/src/utilities/misc/weeksince.m new file mode 100644 index 0000000000000000000000000000000000000000..830d347ebbd749f7bad879a75d13432e34a1051e --- /dev/null +++ b/src/utilities/misc/weeksince.m @@ -0,0 +1,119 @@ +function o = weeksince(y, w, z) % --*-- Unitary tests --*-- + +% Returns the number of ISO weeks since base year z. +% +% INPUTS +% - y [integer] scalar or vector, the year. +% - w [integer] scalar or vector, the week. +% - z [integer] scalar, base year. +% +% OUTPUTS +% - o [integer] scalar or vector, number of weeks. + +% Copyright © 2021 Dynare Team +% +% This file is part of Dynare. +% +% Dynare 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. +% +% Dynare 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 Dynare. If not, see <https://www.gnu.org/licenses/>. + +if nargin<3 + z = 0; % Default value for base year. +end + +n = zeros(length(y), 1); + +id = y-1>=z; + +if ~isempty(id) + n(id) = longyearsince(y(id)-1, z); +end + +o = 52*(y-z)+n+w; + +return + +%@test:1 +try + w = weeksince(2001, 1, 2000); + t(1) = true; +catch + t(1) = false; +end + +if t(1) + t(2) = w==53; +end + +T = all(t); +%@eof:1 + +%@test:2 +try + w = weeksince(2002, 1, 2000); + t(1) = true; +catch + t(1) = false; +end + +if t(1) + t(2) = w==105; +end + +T = all(t); +%@eof:2 + +%@test:3 +try + w = weeksince(2003, 1, 2000); + t(1) = true; +catch + t(1) = false; +end + +if t(1) + t(2) = w==157; +end + +T = all(t); +%@eof:3 + +%@test:4 +try + w = weeksince(2004, 1, 2000); + t(1) = true; +catch + t(1) = false; +end + +if t(1) + t(2) = w==209; +end + +T = all(t); +%@eof:4 + +%@test:5 +try + w = weeksince(2005, 1, 2000); % 2004 is a long year (53 weeks). + t(1) = true; +catch + t(1) = false; +end + +if t(1) + t(2) = w==262; +end + +T = all(t); +%@eof:5 \ No newline at end of file