5687
|
1 ## Copyright (C) 2000, 2001, 2004, 2005 Paul Kienzle |
|
2 ## |
|
3 ## This file is part of Octave. |
|
4 ## |
|
5 ## Octave is free software; you can redistribute it and/or modify it |
|
6 ## under the terms of the GNU General Public License as published by |
7016
|
7 ## the Free Software Foundation; either version 3 of the License, or (at |
|
8 ## your option) any later version. |
5687
|
9 ## |
|
10 ## Octave is distributed in the hope that it will be useful, but |
|
11 ## WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 ## General Public License for more details. |
|
14 ## |
|
15 ## You should have received a copy of the GNU General Public License |
7016
|
16 ## along with Octave; see the file COPYING. If not, see |
|
17 ## <http://www.gnu.org/licenses/>. |
5687
|
18 |
|
19 ## -*- texinfo -*- |
|
20 ## @deftypefn {Function File} {@var{v} =} datevec (@var{date}) |
|
21 ## @deftypefnx {Function File} {@var{v} =} datevec (@var{date}, @var{f}) |
|
22 ## @deftypefnx {Function File} {@var{v} =} datevec (@var{date}, @var{p}) |
|
23 ## @deftypefnx {Function File} {@var{v} =} datevec (@var{date}, @var{f}, @var{p}) |
|
24 ## @deftypefnx {Function File} {[@var{y}, @var{m}, @var{d}, @var{h}, @var{mi}, @var{s}] =} datevec (@dots{}) |
|
25 ## Convert a serial date number (see @code{datenum}) or date string (see |
|
26 ## @code{datestr}) into a date vector. |
|
27 ## |
|
28 ## A date vector is a row vector with six members, representing the year, |
|
29 ## month, day, hour, minute, and seconds respectively. |
|
30 ## |
|
31 ## @var{f} is the format string used to interpret date strings |
|
32 ## (see @code{datestr}). |
|
33 ## |
|
34 ## @var{p} is the year at the start of the century in which two-digit years |
|
35 ## are to be interpreted in. If not specified, it defaults to the current |
|
36 ## year minus 50. |
|
37 ## @seealso{datenum, datestr, date, clock, now} |
|
38 ## @end deftypefn |
|
39 |
|
40 ## Algorithm: Peter Baum (http://vsg.cape.com/~pbaum/date/date0.htm) |
|
41 |
|
42 ## Author: pkienzle <pkienzle@users.sf.net> |
|
43 ## Modified: bdenney <bill@givebillmoney.com> |
|
44 ## Created: 10 October 2001 (CVS) |
|
45 ## Adapted-By: William Poetra Yoga Hadisoeseno <williampoetra@gmail.com> |
|
46 |
|
47 ## The function __date_str2vec__ is based on datesplit by Bill Denney. |
|
48 |
|
49 function [y, m, d, h, mi, s] = datevec (date, varargin) |
|
50 |
|
51 persistent std_formats nfmt; |
|
52 |
|
53 if (isempty (std_formats)) |
|
54 std_formats = cell (); |
|
55 nfmt = 0; |
|
56 std_formats{++nfmt} = "dd-mmm-yyyy HH:MM:SS"; # 0 |
|
57 std_formats{++nfmt} = "dd-mmm-yyyy"; # 1 |
|
58 std_formats{++nfmt} = "mm/dd/yy"; # 2 |
|
59 std_formats{++nfmt} = "mm/dd"; # 6 |
|
60 std_formats{++nfmt} = "HH:MM:SS"; # 13 |
|
61 std_formats{++nfmt} = "HH:MM:SS PM"; # 14 |
|
62 std_formats{++nfmt} = "HH:MM"; # 15 |
|
63 std_formats{++nfmt} = "HH:MM PM"; # 16 |
|
64 std_formats{++nfmt} = "mm/dd/yyyy"; # 23 |
6044
|
65 std_formats{++nfmt} = "mmm-dd-yyyy HH:MM:SS"; |
|
66 std_formats{++nfmt} = "mmm-dd-yyyy"; |
|
67 std_formats{++nfmt} = "dd mmm yyyy HH:MM:SS"; |
|
68 std_formats{++nfmt} = "dd mmm yyyy"; |
|
69 std_formats{++nfmt} = "mmm dd yyyy HH:MM:SS"; |
|
70 std_formats{++nfmt} = "mmm dd yyyy"; |
|
71 std_formats{++nfmt} = "dd.mmm.yyyy HH:MM:SS"; |
|
72 std_formats{++nfmt} = "dd.mmm.yyyy"; |
|
73 std_formats{++nfmt} = "mmm.dd.yyyy HH:MM:SS"; |
|
74 std_formats{++nfmt} = "mmm.dd.yyyy"; |
|
75 |
|
76 # custom formats |
5687
|
77 std_formats{++nfmt} = "mmmyy"; # 12 |
|
78 std_formats{++nfmt} = "mm/dd/yyyy HH:MM"; |
|
79 endif |
|
80 |
|
81 if (nargin < 1 || nargin > 3) |
6046
|
82 print_usage (); |
5687
|
83 endif |
|
84 |
|
85 switch (nargin) |
|
86 case 1 |
|
87 f = []; |
|
88 p = []; |
|
89 case 2 |
|
90 if (ischar (varargin{1})) |
|
91 f = varargin{1}; |
|
92 p = []; |
|
93 else |
|
94 f = []; |
|
95 p = varargin{1}; |
|
96 endif |
|
97 case 3 |
|
98 f = varargin{1}; |
|
99 p = varargin{2}; |
|
100 endswitch |
|
101 |
|
102 if (isempty (f)) |
|
103 f = -1; |
|
104 endif |
|
105 |
|
106 if (isempty (p)) |
|
107 p = (localtime (time)).year + 1900 - 50; |
|
108 endif |
|
109 |
|
110 if (ischar (date)) |
|
111 t = date; |
|
112 date = cell (1); |
|
113 date{1} = t; |
|
114 endif |
|
115 |
|
116 if (iscell (date)) |
|
117 |
|
118 nd = numel (date); |
|
119 |
|
120 y = m = d = h = mi = s = zeros (nd, 1); |
|
121 |
|
122 if (f == -1) |
|
123 for k = 1:nd |
|
124 found = false; |
|
125 for l = 1:nfmt |
|
126 [found y(k) m(k) d(k) h(k) mi(k) s(k)] = __date_str2vec__ (date{k}, std_formats{l}, p); |
|
127 if (found) |
|
128 break; |
|
129 endif |
|
130 endfor |
|
131 if (! found) |
|
132 error ("datevec: none of the standard formats match the date string"); |
|
133 endif |
|
134 endfor |
|
135 else |
|
136 for k = 1:nd |
|
137 [found y(k) m(k) d(k) h(k) mi(k) s(k)] = __date_str2vec__ (date{k}, f, p); |
|
138 if (! found) |
|
139 error ("datevec: date not parsed correctly with given format"); |
|
140 endif |
|
141 endfor |
|
142 endif |
|
143 |
|
144 else |
|
145 |
|
146 date = date(:); |
|
147 |
|
148 ## Move day 0 from midnight -0001-12-31 to midnight 0000-3-1 |
|
149 z = floor (date) - 60; |
|
150 ## Calculate number of centuries; K1 = 0.25 is to avoid rounding problems. |
|
151 a = floor ((z - 0.25) / 36524.25); |
|
152 ## Days within century; K2 = 0.25 is to avoid rounding problems. |
|
153 b = z - 0.25 + a - floor (a / 4); |
|
154 ## Calculate the year (year starts on March 1). |
|
155 y = floor (b / 365.25); |
|
156 ## Calculate day in year. |
|
157 c = fix (b - floor (365.25 * y)) + 1; |
|
158 ## Calculate month in year. |
|
159 m = fix ((5 * c + 456) / 153); |
|
160 d = c - fix ((153 * m - 457) / 5); |
|
161 ## Move to Jan 1 as start of year. |
|
162 ++y(m > 12); |
|
163 m(m > 12) -= 12; |
|
164 |
5859
|
165 ## Convert hour-minute-seconds. Attempt to account for precision of |
|
166 ## datenum format. |
|
167 |
|
168 fracd = date - floor (date); |
5873
|
169 tmps = abs (eps*86400*date); |
|
170 tmps(tmps == 0) = 1; |
|
171 srnd = 2 .^ floor (- log2 (tmps)); |
|
172 s = round (86400 * fracd .* srnd) ./ srnd; |
5687
|
173 h = floor (s / 3600); |
|
174 s = s - 3600 * h; |
|
175 mi = floor (s / 60); |
|
176 s = s - 60 * mi; |
|
177 |
|
178 endif |
|
179 |
|
180 if (nargout <= 1) |
5873
|
181 y = [y, m, d, h, mi, s]; |
5687
|
182 endif |
|
183 |
|
184 ### endfunction |
|
185 |
|
186 function [found, y, m, d, h, mi, s] = __date_str2vec__ (ds, f, p) |
|
187 |
|
188 # Play safe with percent signs |
|
189 f = strrep(f, "%", "%%"); |
|
190 |
|
191 ## dates to lowercase (note: we cannot convert MM to mm) |
|
192 f = strrep (f, "YYYY", "yyyy"); |
|
193 f = strrep (f, "YY", "yy"); |
|
194 f = strrep (f, "QQ", "qq"); |
|
195 f = strrep (f, "MMMM", "mmmm"); |
|
196 f = strrep (f, "MMM", "mmm"); |
|
197 f = strrep (f, "DDDD", "dddd"); |
|
198 f = strrep (f, "DDD", "ddd"); |
|
199 f = strrep (f, "DD", "dd"); |
|
200 ## times to uppercase (also cannot convert mm to MM) |
|
201 f = strrep (f, "hh", "HH"); |
|
202 f = strrep (f, "ss", "SS"); |
|
203 f = strrep (f, "pm", "PM"); |
|
204 f = strrep (f, "am", "AM"); |
|
205 |
|
206 ## right now, the format string may only contain these tokens: |
|
207 ## yyyy 4 digit year |
|
208 ## yy 2 digit year |
|
209 ## mmmm month name, full |
|
210 ## mmm month name, abbreviated |
|
211 ## mm month number |
|
212 ## dddd weekday name, full |
|
213 ## ddd weekday name, abbreviated |
|
214 ## dd date |
|
215 ## HH hour |
|
216 ## MM minutes |
|
217 ## SS seconds |
|
218 ## PM AM/PM |
|
219 ## AM AM/PM |
|
220 |
|
221 if (! isempty (strfind (f, "PM")) || ! isempty (strfind (f, "AM"))) |
|
222 ampm = true; |
|
223 else |
|
224 ampm = false; |
|
225 endif |
|
226 |
|
227 # date part |
|
228 f = strrep (f, "yyyy", "%Y"); |
|
229 f = strrep (f, "yy", "%y"); |
|
230 f = strrep (f, "mmmm", "%B"); |
|
231 f = strrep (f, "mmm", "%b"); |
|
232 f = strrep (f, "mm", "%m"); |
|
233 f = strrep (f, "dddd", "%A"); |
|
234 f = strrep (f, "ddd", "%a"); |
|
235 f = strrep (f, "dd", "%d"); |
|
236 |
|
237 # time part |
|
238 if (ampm) |
|
239 f = strrep (f, "HH", "%I"); |
|
240 f = strrep (f, "PM", "%p"); |
|
241 f = strrep (f, "AM", "%p"); |
|
242 else |
|
243 f = strrep (f, "HH", "%H"); |
|
244 endif |
|
245 f = strrep (f, "MM", "%M"); |
|
246 f = strrep (f, "SS", "%S"); |
|
247 |
|
248 [tm, nc] = strptime (ds, f); |
|
249 |
|
250 if (nc == length (ds) + 1) |
|
251 y = tm.year + 1900; m = tm.mon + 1; d = tm.mday; |
|
252 h = tm.hour; mi = tm.min; s = tm.sec + tm.usec / 1e6; |
|
253 found = true; |
|
254 rY = rindex (f, "%Y"); |
|
255 ry = rindex (f, "%y"); |
|
256 if (rY < ry) |
|
257 if (y > 1999) |
|
258 y -= 2000; |
|
259 else |
|
260 y -= 1900; |
|
261 endif |
|
262 y += p - mod (p, 100); |
|
263 if (y < p) |
|
264 y += 100; |
|
265 endif |
|
266 endif |
|
267 # check whether we need to give default values |
|
268 # possible error when string contains "%%" |
|
269 fy = rY || ry; |
|
270 fm = index (f, "%m") || index (f, "%b") || index (f, "%B"); |
|
271 fd = index (f, "%d") || index (f, "%a") || index (f, "%A"); |
|
272 fh = index (f, "%H") || index (f, "%I"); |
|
273 fmi = index (f, "%M"); |
|
274 fs = index (f, "%S"); |
|
275 if (! fy && ! fm && ! fd) |
|
276 tvm = localtime (time ()); ## tvm: this very moment |
|
277 y = tvm.year + 1900; |
|
278 m = tvm.mon + 1; |
|
279 d = tvm.mday; |
|
280 elseif (! fy && fm && fd) |
|
281 tvm = localtime (time ()); ## tvm: this very moment |
|
282 y = tvm.year + 1900; |
|
283 elseif (fy && fm && ! fd) |
|
284 tvm = localtime (time ()); ## tvm: this very moment |
|
285 d = 1; |
|
286 endif |
|
287 if (! fh && ! fmi && ! fs) |
|
288 h = mi = s = 0; |
|
289 elseif (fh && fmi && ! fs) |
|
290 s = 0; |
|
291 endif |
|
292 else |
|
293 y = m = d = h = mi = s = 0; |
|
294 found = false; |
|
295 endif |
|
296 |
|
297 ### endfunction |
|
298 |
|
299 %!shared nowvec |
|
300 %! nowvec = datevec (now); # Some tests could fail around midnight! |
|
301 # tests for standard formats: 0, 1, 2, 6, 13, 14, 15, 16, 23 |
|
302 %!assert(datevec("07-Sep-2000 15:38:09"),[2000,9,7,15,38,9]); |
|
303 %!assert(datevec("07-Sep-2000"),[2000,9,7,0,0,0]); |
|
304 %!assert(datevec("09/07/00"),[2000,9,7,0,0,0]); |
|
305 %!assert(datevec("09/13"),[nowvec(1),9,13,0,0,0]); |
|
306 %!assert(datevec("15:38:09"),[nowvec(1:3),15,38,9]); |
|
307 %!assert(datevec("3:38:09 PM"),[nowvec(1:3),15,38,9]); |
|
308 %!assert(datevec("15:38"),[nowvec(1:3),15,38,0]); |
|
309 %!assert(datevec("03:38 PM"),[nowvec(1:3),15,38,0]); |
|
310 %!assert(datevec("03/13/1962"),[1962,3,13,0,0,0]); |
|
311 # other tests |
|
312 %!assert(all(datenum(datevec([-1e4:1e4]))==[-1e4:1e4]')) |
|
313 %!test |
|
314 %! t = linspace (-2e5, 2e5, 10993); |
5860
|
315 %! assert (all (abs (datenum (datevec (t)) - t') < 1e-5)); |
5687
|
316 # demos |
|
317 %!demo |
|
318 %! datevec (now ()) |