1 //
2 // aegis - project change supervisor
3 // Copyright (C) 1994-1997, 1999, 2003-2008, 2012 Peter Miller
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published
7 // by the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but 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 this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18 
19 #include <common/ac/assert.h>
20 
21 #include <common/now.h>
22 #include <common/trace.h>
23 #include <libaegis/aer/expr.h>
24 #include <libaegis/aer/func/now.h>
25 #include <libaegis/aer/value/error.h>
26 #include <libaegis/aer/value/integer.h>
27 #include <libaegis/aer/value/real.h>
28 #include <libaegis/aer/value/time.h>
29 #include <libaegis/sub.h>
30 
31 
~rpt_func_now()32 rpt_func_now::~rpt_func_now()
33 {
34 }
35 
36 
rpt_func_now()37 rpt_func_now::rpt_func_now()
38 {
39 }
40 
41 
42 rpt_func::pointer
create()43 rpt_func_now::create()
44 {
45     return pointer(new rpt_func_now());
46 }
47 
48 
49 const char *
name() const50 rpt_func_now::name()
51     const
52 {
53     return "now";
54 }
55 
56 
57 bool
optimizable() const58 rpt_func_now::optimizable()
59     const
60 {
61     return false;
62 }
63 
64 
65 bool
verify(const rpt_expr::pointer & ep) const66 rpt_func_now::verify(const rpt_expr::pointer &ep)
67     const
68 {
69     return (ep->get_nchildren() == 0);
70 }
71 
72 
73 rpt_value::pointer
run(const rpt_expr::pointer &,size_t,rpt_value::pointer *) const74 rpt_func_now::run(const rpt_expr::pointer &, size_t, rpt_value::pointer *)
75     const
76 {
77     return rpt_value_time::create(now());
78 }
79 
80 
81 #define WORKING_DAYS_PER_WEEK 5
82 #define HOURS_PER_WORKING_DAY 7.5
83 #define SECONDS_PER_WORKING_DAY (long)(HOURS_PER_WORKING_DAY * 60L * 60L)
84 #define SECONDS_PER_DAY (24L * 60L * 60L)
85 
86 
87 double
working_days(time_t start,time_t finish)88 working_days(time_t start, time_t finish)
89 {
90     //
91     // Flip it end-for-end if they gave it the wrong way round.
92     //
93     trace(("working_days(start = %ld, finish = %ld)\n{\n",
94            (long)start, (long)finish));
95     trace(("start = %s", ctime(&start)));
96     trace(("finish = %s", ctime(&finish)));
97     if (start > finish)
98     {
99         time_t tmp = start;
100         finish = start;
101         start = tmp;
102     }
103 
104     //
105     // Get the current week say.
106     // Adjust it so that MON=0 thru SUN=6
107     //
108     int wday = localtime(&start)->tm_wday;
109     wday = (wday + 6) % 7;
110 
111     long working_days_whole = 0;
112     double working_days_frac = 0;
113 
114     //
115     // Treat the first day specially, in case it is a day of the
116     // weekend.
117     //
118     if ((long)start + SECONDS_PER_WORKING_DAY <= (long)finish)
119     {
120         working_days_whole++;
121         start += SECONDS_PER_DAY;
122         wday = (wday + 1) % 7;
123     }
124 
125     //
126     // Loop over the intervening days, incrimenting the counter for
127     // any day that is not a day of the weekend.
128     //
129     while ((long)start + SECONDS_PER_WORKING_DAY <= (long)finish)
130     {
131         if (wday < WORKING_DAYS_PER_WEEK)
132             working_days_whole++;
133         start += SECONDS_PER_DAY;
134         wday = (wday + 1) % 7;
135     }
136 
137     //
138     // Always do the fraction, even if it is a day of the weekend.
139     //
140     assert((long)finish - (long)start < SECONDS_PER_WORKING_DAY);
141     if (start < finish)
142     {
143         working_days_frac = (finish - start) / (double)SECONDS_PER_WORKING_DAY;
144     }
145 
146     //
147     // done
148     //
149     working_days_frac += working_days_whole;
150     trace(("return %.10g;\n", working_days_frac));
151     trace(("}\n"));
152     return working_days_frac;
153 }
154 
155 
~rpt_func_working_days()156 rpt_func_working_days::~rpt_func_working_days()
157 {
158 }
159 
160 
rpt_func_working_days()161 rpt_func_working_days::rpt_func_working_days()
162 {
163 }
164 
165 
166 rpt_func::pointer
create()167 rpt_func_working_days::create()
168 {
169     return pointer(new rpt_func_working_days());
170 }
171 
172 
173 const char *
name() const174 rpt_func_working_days::name()
175     const
176 {
177     return "working_days";
178 }
179 
180 
181 bool
optimizable() const182 rpt_func_working_days::optimizable()
183     const
184 {
185     return true;
186 }
187 
188 
189 bool
verify(const rpt_expr::pointer & ep) const190 rpt_func_working_days::verify(const rpt_expr::pointer &ep)
191     const
192 {
193     return (ep->get_nchildren() == 2);
194 }
195 
196 
197 rpt_value::pointer
run(const rpt_expr::pointer & ep,size_t,rpt_value::pointer * argv) const198 rpt_func_working_days::run(const rpt_expr::pointer &ep, size_t,
199     rpt_value::pointer *argv) const
200 {
201     rpt_value::pointer t1 = rpt_value::integerize(argv[0]);
202     rpt_value_integer *t1ip = dynamic_cast<rpt_value_integer *>(t1.get());
203     if (!t1ip)
204     {
205         sub_context_ty sc;
206         sc.var_set_charstar("Function", "working_days");
207         sc.var_set_long("Number", 1);
208         sc.var_set_charstar("Name", argv[0]->name());
209         nstring s
210         (
211             sc.subst_intl
212             (
213                 i18n("$function: argument $number: time value required "
214                     "(was given $name)")
215             )
216         );
217         return rpt_value_error::create(ep->get_pos(), s);
218     }
219 
220     rpt_value::pointer t2 = rpt_value::integerize(argv[1]);
221     rpt_value_integer *t2ip = dynamic_cast<rpt_value_integer *>(t2.get());
222     if (!t2ip)
223     {
224         sub_context_ty sc;
225         sc.var_set_charstar("Function", "working_days");
226         sc.var_set_long("Number", 2);
227         sc.var_set_charstar("Name", argv[1]->name());
228         nstring s
229         (
230             sc.subst_intl
231             (
232                 i18n("$function: argument $number: time value required "
233                     "(was given $name)")
234             )
235         );
236         return rpt_value_error::create(ep->get_pos(), s);
237     }
238 
239     return rpt_value_real::create(working_days(t1ip->query(), t2ip->query()));
240 }
241 
242 
243 // vim: set ts=8 sw=4 et :
244