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