4 namespace Wv
.Schedulator
6 public class DateSlider
: ICloneable
8 double _hours_per_week
= 40;
9 public double hours_per_week
11 get { return _hours_per_week; }
14 // Sunday first, to match the enum DayOfWeek
15 double[] _hours_per_day
= {0,8,8,8,8,8,0}
;
16 public double[] hours_per_day
18 get { return _hours_per_day; }
21 double _loadfactor
= 1.0;
22 public double loadfactor
24 get { return _loadfactor; }
28 public DateSlider
new_hours_per_day(double[] hours_per_day
)
30 DateSlider d
= (DateSlider
)this.Clone();
32 d
._hours_per_day
= (double[])hours_per_day
.Clone();
33 d
._hours_per_week
= 0;
34 for (int i
= 0; i
< 7; i
++)
36 if (d
._hours_per_day
[i
] < 0 || d
._hours_per_day
[i
] > 24)
37 throw new ArgumentException("Each day can have 0 "
39 d
._hours_per_week
+= d
._hours_per_day
[i
];
41 if (d
._hours_per_week
< 1)
42 throw new ArgumentException("A week needs "
43 + "at least 1 hour.");
47 public DateSlider
new_loadfactor(double loadfactor
)
49 DateSlider d
= (DateSlider
)this.Clone();
50 d
._loadfactor
= loadfactor
;
56 // double[] x = {0,8,8,8,8,8,0};
57 // _hours_per_day = x;
62 DateSlider d
= (DateSlider
)this.MemberwiseClone();
63 d
._hours_per_day
= (double[])this.hours_per_day
.Clone();
67 public override string ToString()
69 return String
.Format("(loadfactor={0:f2} "
70 + "hours=[{1} {2} {3} {4} {5} {6} {7}])",
81 public override bool Equals(object _y
)
83 DateSlider y
= (DateSlider
)_y
;
84 return hours_per_day
== y
.hours_per_day
85 && loadfactor
== y
.loadfactor
;
88 public override int GetHashCode()
90 return hours_per_day
.GetHashCode() + loadfactor
.GetHashCode();
93 public DateTime
add(DateTime point
, TimeSpan span
)
95 WvLog log
= new WvLog("slider", WvLog
.L
.Debug5
);
96 log
.print("* {0} + {1}\n", point
, span
.TotalHours
);
98 int sign
= (span
.Ticks
< 0) ? -1 : 1;
99 bool less_one
= false;
101 // speed through times >= 1 week
102 double hpw
= hours_per_week
/ loadfactor
;
103 while (Math
.Abs(span
.TotalHours
) >= hpw
)
105 log
.print("W {0} + {1} ({2})\n", point
, span
.TotalHours
, hpw
);
106 point
= point
.AddDays(7*sign
);
107 span
= span
.Add(TimeSpan
.FromHours(-hpw
*sign
));
110 // inside a week, count a day at a time
111 while (Math
.Abs(span
.TotalHours
) > 0.01)
113 int day
= (int)point
.DayOfWeek
;
115 // we might be partway through the current day...
116 double dayfraction
= point
.TimeOfDay
.TotalHours
/ 24.0;
119 if (dayfraction
> 0.999)
125 // we want the remaining part of the day
126 dayfraction
= 1.0 - dayfraction
;
130 if (dayfraction
< 0.001)
133 if (day
< 0) day
= 6;
138 // we want the expired part of the day: keep dayfraction
141 double hpd
= hours_per_day
[day
] * dayfraction
/ loadfactor
;
143 log
.print("D {0} + {1} ({2})\n", point
, span
.TotalHours
, hpd
);
144 if (Math
.Abs(span
.TotalHours
) >= hpd
)
146 // avoid rounding errors by forcing the date
147 if (sign
> 0 || less_one
)
148 point
= point
.Date
.AddDays(1*sign
);
151 span
= span
.Add(TimeSpan
.FromHours(-hpd
*sign
));
155 point
= point
.AddHours(span
.TotalHours
/hpd
157 span
= TimeSpan
.Zero
;
161 log
.print(": {0} + {1}\n", point
, span
.TotalHours
);
163 // ah, rounding errors. The above should make things work out
164 // to within the nearest minute or so, which is close enough(tm).
165 double th
= point
.TimeOfDay
.TotalHours
;
166 point
= point
.AddHours(Math
.Round(th
, 1) - th
+ 0.5/60.0/60.0);
167 point
= new DateTime(point
.Year
, point
.Month
, point
.Day
,
168 point
.Hour
, point
.Minute
, 0, 0);
169 log
.print(". {0} + {1} ({2})\n",
170 point
, span
.TotalHours
, Math
.Round(th
, 1));
174 // returns d = x - y, such that x = add(y, d).
175 // Note that if day 'x' has zero working hours, this doesn't make
176 // sense, so we choose the closest timespan that will get us up
177 // to, but not including, x.
178 public TimeSpan
diff(DateTime x
, DateTime y
)
180 WvLog log
= new WvLog("slider", WvLog
.L
.Debug5
);
183 DateTime point
= y
, end
= x
;
184 TimeSpan result
= TimeSpan
.Zero
;
188 TimeSpan remain
= end
- point
;
189 double hpd
= hours_per_day
[(int)point
.DayOfWeek
];
191 if (remain
.TotalDays
>= 7)
193 int weeks
= (int)Math
.Round(remain
.TotalDays
/ 7);
194 point
+= TimeSpan
.FromDays(weeks
* 7);
195 result
+= TimeSpan
.FromHours(
196 weeks
* hours_per_week
/ loadfactor
);
198 else if (remain
.TotalHours
>= 24)
200 point
+= TimeSpan
.FromDays(1);
201 result
+= TimeSpan
.FromHours(hpd
/ loadfactor
);
203 else if (remain
.TotalHours
> 0)
205 double dayfraction
= remain
.TotalHours
/ 24;
207 result
+= TimeSpan
.FromHours(
208 dayfraction
* hpd
/ loadfactor
);
212 log
.print("result: {0} hours\n", result
.TotalHours
);