4b4796cfd9ab30f354a9e1d954d32f29b6f22788
[ccsdk/features.git] /
1 /**
2  * Copyright 2010-2013 Ben Birch
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this software except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /*!
17  * date-range-parser.js
18  * Contributed to the Apache Software Foundation by:
19  *    Ben Birch - Aconex
20  * fork me at https://github.com/mobz/date-range-parser
21
22 Licensed to the Apache Software Foundation (ASF) under one
23 or more contributor license agreements.  See the NOTICE file
24 distributed with this work for additional information
25 regarding copyright ownership.  The ASF licenses this file
26 to you under the Apache License, Version 2.0 (the
27 "License"); you may not use this file except in compliance
28 with the License.  You may obtain a copy of the License at
29
30       http://www.apache.org/licenses/LICENSE-2.0
31
32 Unless required by applicable law or agreed to in writing,
33 software distributed under the License is distributed on an
34 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
35 KIND, either express or implied.  See the License for the
36 specific language governing permissions and limitations
37 under the License.
38
39 */
40
41 (function() {
42
43         var drp = window.dateRangeParser = {};
44
45         drp.defaultRange = 1000 * 60 * 60 * 24;
46
47         drp.now = null; // set a different value for now than the time at function invocation
48
49         drp.parse = function(v) {
50                 try {
51                         var r = drp._parse(v);
52                         r.end && r.end--; // remove 1 millisecond from the final end range
53                 } catch(e) {
54                         r = null;
55                 }
56                 return r;
57         };
58
59         drp.print = function(t, p) {
60                 var format = ["", "-", "-", " ", ":", ":", "."];
61                 var da = makeArray(t);
62                 var str = "";
63                 for(var i = 0; i <= p; i++) {
64                         str += format[i] + (da[i] < 10 ? "0" : "") + da[i];
65                 }
66                 return str;
67         };
68
69         (function() {
70                 drp._relTokens = {};
71
72                 var values = {
73                         "yr"  : 365*24*60*60*1000,
74                         "mon" : 31*24*60*60*1000,
75                         "day" : 24*60*60*1000,
76                         "hr"  : 60*60*1000,
77                         "min" : 60*1000,
78                         "sec" : 1000
79                 };
80
81                 var alias_lu = {
82                         "yr" : "y,yr,yrs,year,years",
83                         "mon" : "mo,mon,mos,mons,month,months",
84                         "day" : "d,dy,dys,day,days",
85                         "hr" : "h,hr,hrs,hour,hours",
86                         "min" : "m,min,mins,minute,minutes",
87                         "sec" : "s,sec,secs,second,seconds"
88                 };
89
90                 for(var key in alias_lu) {
91                         if(alias_lu.hasOwnProperty(key)) {
92                                 var aliases = alias_lu[key].split(",");
93                                 for(var i = 0; i < aliases.length; i++) {
94                                         drp._relTokens[aliases[i]] = values[key];
95                                 }
96                         }
97                 }
98         })();
99
100         function makeArray(d) {
101                 var da = new Date(d);
102                 return [ da.getUTCFullYear(), da.getUTCMonth()+1, da.getUTCDate(), da.getUTCHours(), da.getUTCMinutes(), da.getUTCSeconds(), da.getUTCMilliseconds() ];
103         }
104
105         function fromArray(a) {
106                 var d = [].concat(a); d[1]--;
107                 return Date.UTC.apply(null, d);
108         }
109
110         drp._parse = function parse(v) {
111                 var now = this.now || new Date().getTime();
112
113                 function precArray(d, p, offset) {
114                         var tn = makeArray(d);
115                         tn[p] += offset || 0;
116                         for(var i = p+1; i < 7; i++) {
117                                 tn[i] = i < 3 ? 1 : 0;
118                         }
119                         return tn;
120                 }
121                 function makePrecRange(dt, p, r) {
122                         var ret = { };
123                         ret.start = fromArray(dt);
124                         dt[p] += r || 1;
125                         ret.end = fromArray(dt);
126                         return ret;
127                 }
128                 function procTerm(term) {
129                         var m = term.replace(/\s/g, "").toLowerCase().match(/^([a-z ]+)$|^([ 0-9:-]+)$|^(\d+[a-z]+)$/);
130                         if(m[1]) {      // matches ([a-z ]+)
131                                 function dra(p, o, r) {
132                                         var dt = precArray(now, p, o);
133                                         if(r) {
134                                                 dt[2] -= new Date(fromArray(dt)).getUTCDay();
135                                         }
136                                         return makePrecRange(dt, p, r);
137                                 }
138                                 switch( m[1]) {
139                                         case "now" : return { start: now, end: now, now: now };
140                                         case "today" : return dra( 2, 0 );
141                                         case "thisweek" : return dra( 2, 0, 7 );
142                                         case "thismonth" : return dra( 1, 0 );
143                                         case "thisyear" : return dra( 0, 0 );
144                                         case "yesterday" : return dra( 2, -1 );
145                                         case "lastweek" : return dra( 2, -7, 7 );
146                                         case "lastmonth" : return dra( 1, -1 );
147                                         case "lastyear" : return dra( 0, -1 );
148                                         case "tomorrow" : return dra( 2, 1 );
149                                         case "nextweek" : return dra( 2, 7, 7 );
150                                         case "nextmonth" : return dra( 1, 1 );
151                                         case "nextyear" : return dra(0, 1 );
152                                 }
153                                 throw "unknown token " +  m[1];
154                         } else if(m[2]) { // matches ([ 0-9:-]+)
155                                 dn = makeArray(now);
156                                 var dt = m[2].match(/^(?:(\d{4})(?:\-(\d\d))?(?:\-(\d\d))?)? ?(?:(\d{1,2})(?:\:(\d\d)(?:\:(\d\d))?)?)?$/);
157                                 dt.shift();
158                                 for(var p = 0, z = false, i = 0; i < 7; i++) {
159                                         if(dt[i]) {
160                                                 dn[i] = parseInt(dt[i], 10);
161                                                 p = i;
162                                                 z = true;
163                                         } else {
164                                                 if(z)
165                                                         dn[i] = i < 3 ? 1 : 0;
166                                         }
167                                 }
168                                 return makePrecRange(dn, p);
169                         } else if(m[3]) { // matches (\d+[a-z]{1,4})
170                                 var dr = m[3].match(/(\d+)\s*([a-z]+)/i);
171                                 var n = parseInt(dr[1], 10);
172                                 return { rel: n * drp._relTokens[dr[2]] };
173                         }
174                         throw "unknown term " + term;
175                 }
176
177                 if(!v) {
178                         return { start: null, end: null };
179                 }
180                 var terms = v.split(/\s*([^<>]*[^<>-])?\s*(->|<>|<)?\s*([^<>]+)?\s*/);
181
182                 var term1 = terms[1] ? procTerm(terms[1]) : null;
183                 var op = terms[2] || "";
184                 var term2 = terms[3] ? procTerm(terms[3]) : null;
185
186                 if(op === "<" || op === "->" ) {
187                         if(term1 && !term2) {
188                                 return { start: term1.start, end: null };
189                         } else if(!term1 && term2) {
190                                 return { start: null, end: term2.end };
191                         } else {
192                                 if(term2.rel) {
193                                         return { start: term1.start, end: term1.end + term2.rel };
194                                 } else if(term1.rel) {
195                                         return { start: term2.start - term1.rel, end: term2.end };
196                                 } else {
197                                         return { start: term1.start, end: term2.end };
198                                 }
199                         }
200                 } else if(op === "<>") {
201                         if(!term2) {
202                                 return { start: term1.start - drp.defaultRange, end: term1.end + drp.defaultRange }
203                         } else {
204                                 if(! ("rel" in term2)) throw "second term did not hav a range";
205                                 return { start: term1.start - term2.rel, end: term1.end + term2.rel };
206                         }
207                 } else {
208                         if(term1.rel) {
209                                 return { start: now - term1.rel, end: now + term1.rel };
210                         } else if(term1.now) {
211                                 return { start: term1.now - drp.defaultRange, end: term1.now + drp.defaultRange };
212                         } else {
213                                 return { start: term1.start, end: term1.end };
214                         }
215                 }
216                 throw "could not process value " + v;
217         };
218 })();