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