public static IList <TimeSplit <T> > CalcEventsTimeSplitAggregate <T> (IReadOnlyDictionary <uint, IList <TimeSplit <T> > > dict) { // Calculate aggregate percentages return(dict.Values .SelectMany(_ => _) .GroupBy(ctrldict => ctrldict.StartTime) .OrderBy(g => g.Key) .AsParallel() .Select(g => { var starttime = g.Key; var endtime = g.FirstOrDefault()?.EndTime ?? default(DateTimeOffset); var num = g.Count(); var r = new TimeSplit <T>( g.SelectMany(t => t.Data) .GroupBy(kv => kv.Key, kv => kv.Value) .ToDictionary(x => x.Key, x => x.Sum(p => p) / num) ); r.StartTime = starttime; r.EndTime = endtime; return r; }).OrderBy(x => x.StartTime) .ToList()); }
public void CheckTimeSplit() { var checkTimeList = new List <string> { "10:11:01", "12:03:34", "14:05:04", "18:07:21" }; var splitTime = new TimeSplit(checkTimeList); Assert.True(splitTime.IsTimeSplit); }
public async Task <IReadOnlyDictionary <uint, IList <TimeSplit <T> > > > GetEventsTimeSplit <T> (DateTimeOffset from, DateTimeOffset to, Func <EventX, T> grouping, string field, T nullValue, bool skipNulls, TimeSpan step, TimeSpan timezone, string orgId, ICollection <uint> controllers) { if (from > to) { throw new ArgumentOutOfRangeException(nameof(from), "Start date must not be later than the end date."); } if (grouping == null) { throw new ArgumentNullException(nameof(grouping)); } var clist = await Utils.GetValidControllersAsync(m_DB, orgId).ConfigureAwait(false); if (clist == null) { return(null); } if (controllers == null || controllers.Contains(0)) { controllers = clist.Select(c => (uint)c.ID).ToList(); } else { var newlist = clist.Select(c => (uint)c.ID).Intersect(controllers).ToList(); // No controllers selected if (newlist.Count <= 0 || newlist.Count < controllers.Count) { return(null); } controllers = newlist; } var incrementdate = Utils.GetIncrementDateFunc(step, timezone); var result = new ConcurrentDictionary <uint, ConcurrentBag <EventX> >(controllers.Select(id => new KeyValuePair <uint, ConcurrentBag <EventX> >(id, new ConcurrentBag <EventX>()))); foreach (var controllerId in controllers) { // Start selecting one day before the lower bound var r = await GetDataAsync <EventX>(Storage.EventsTable, from.AddDays(-1), to, null, Sorting.None, orgId, controllerId, field, skipNulls).ConfigureAwait(false); if (r == null) { return(null); } foreach (var ev in r) { result.AddOrUpdate(ev.Controller, new ConcurrentBag <EventX>() { ev }, (k, v) => { v.Add(ev); return(v); }); } } // Process all the controllers in parallel var dict = new ConcurrentDictionary <uint, List <Dictionary <T, double> > >(); var slots = 1; result.AsParallel().ForAll(ctrl => { var xlist = ctrl.Value.OrderBy(ev => ev.Time).ThenBy(ev => ev.RowKey).ToList(); var ctrldictlist = dict.GetOrAdd(ctrl.Key, x => new List <Dictionary <T, double> >()); if (step == default(TimeSpan)) { step = to - from; } var lastdate = from; var laststate = default(T); var hasvalue = false; var slot = 0; for (var lower = from; lower < to; lower = incrementdate(lower, step), slot++) { var upper = incrementdate(lower, step); if (upper > to) { upper = to; } if (slots <= slot) { slots = slot + 1; } var ctrldict = new Dictionary <T, double>(); ctrldictlist.Add(ctrldict); // Add a dummy record at the end to make sure we get the very last segment foreach (var entry in xlist.Concat(new[] { new EventX() })) { var newstate = grouping(entry); if (newstate == null) { newstate = nullValue; } if (entry.Time < lastdate) { // Value below the lower bound laststate = newstate; hasvalue = true; continue; } else if (!hasvalue) { // Value within range but there is still no state - try to estimate if (typeof(T) == typeof(bool) || newstate is bool) { laststate = (T)Convert.ChangeType(!((bool)Convert.ChangeType(newstate, typeof(bool))), typeof(T)); } else { laststate = nullValue; } hasvalue = true; } // Value in range var interval = entry.Time - lastdate; if (entry.Time >= upper) { interval = upper - lastdate; lastdate = upper; } else { lastdate = entry.Time; } if (ctrldict.ContainsKey(laststate)) { ctrldict[laststate] += interval.TotalMilliseconds; } else { ctrldict[laststate] = interval.TotalMilliseconds; } if (entry.Time >= upper) { break; } else { laststate = newstate; } } } }); return(dict.ToDictionary(kv => kv.Key, kv => { var startdate = from; return kv.Value.Select((entry, x) => { var enddate = (step == TimeSpan.Zero || x >= slots - 1) ? to : incrementdate(startdate, step); var timerange = (enddate - startdate).TotalMilliseconds; var r = new TimeSplit <T>(entry.ToDictionary(t => t.Key, t => t.Value / timerange)); r.StartTime = startdate; r.EndTime = enddate; startdate = incrementdate(startdate, step); return r; }).ToList() as IList <TimeSplit <T> >; })); }
void addWkTimeSegment(DateTime timeA, DateTime timeB, EvOfIntFlag eoiA, EvOfIntFlag eoiB, Brush brh, ref TimeSplit ts) { if (eoiA == EvOfIntFlag.ScreenSaverrUp && eoiB == EvOfIntFlag.BootAndWakeUps) { eoiB = EvOfIntFlag.ScreenSaverrUp; // ignore odd pwr-on during scrsvr runs. } if (eoiA == EvOfIntFlag.BootAndWakeUps && eoiB == EvOfIntFlag.ScreenSaverrDn) { eoiA = EvOfIntFlag.ScreenSaverrUp; // ignore odd pwr-on during scrsvr runs. } add_________Time(timeA, timeB, eoiA, eoiB, ref ts); var angleA = _aw * (eoiA == EvOfIntFlag.ScreenSaverrUp ? timeA.AddSeconds(-Ssto_GpSec).TimeOfDay.TotalDays : timeA.TimeOfDay.TotalDays); // for ss up - start idle line 2 min prior var angleB = _aw * (eoiB == EvOfIntFlag.ScreenSaverrUp ? timeB.AddSeconds(-Ssto_GpSec).TimeOfDay.TotalDays : timeB.TimeOfDay.TotalDays); // for ss dn - end work line 2 min prior var hgt = eoiA == EvOfIntFlag.Day1stAmbiguos ? (_ah / 9) : eoiA == EvOfIntFlag.ScreenSaverrUp ? (_ah / 7) : eoiA == EvOfIntFlag.ScreenSaverrDn ? (_ah / 1) : eoiA == EvOfIntFlag.BootAndWakeUps ? (_ah / 1) : eoiA == EvOfIntFlag.Who_Knows_What ? (_ah / 8) : 0; var isUp = eoiA == EvOfIntFlag.ScreenSaverrDn || eoiA == EvOfIntFlag.BootAndWakeUps; var top = _ah - hgt; var wid = Math.Abs(angleB - angleA); var time = TimeSpan.FromDays(wid / _aw); addRectangle(top, hgt, angleA, wid, brh, $"Span: {time:h\\:mm\\:ss} => {wid:N0} pxl."); if (wid > .005 * _aw) { var isBig = time > TimeSpan.FromHours(1); addUiElnt( isUp ? 2 : -1, angleB - (isBig ? 28 : 20), new TextBlock { Text = isBig ? $"{time:h\\:mm}" : $"{time,3:\\:m}", FontSize = isUp ? 14 : 12, Foreground = isUp ? Brushes.LimeGreen : Brushes.DodgerBlue, ToolTip = $"Span: {time:h\\:mm\\:ss} => {wid:N0} pxl." });
void add_________Time(DateTime timeA, DateTime timeB, EvOfIntFlag eoiA, EvOfIntFlag eoiB, ref TimeSplit ts) { if (eoiA == EvOfIntFlag.ScreenSaverrDn || eoiA == EvOfIntFlag.BootAndWakeUps) { ts.WorkedFor += (timeB - timeA); } else { ts.IdleOrOff += (timeB - timeA); } }
}); //addArcDtl(hgt, left, width); void drawUpDnLine(DateTime trgDate, string pc, string rgb) { var pcClr = new SolidColorBrush((Color)ColorConverter.ConvertFromString(rgb)); var ts = new TimeSplit(); //..Trace.Write($">>>-\tdrawUpDnLine(): {trgDate:d} ->> {pc,-16} \t"); tbSummary.Text = "$@#"; try { _ah = canvasBar.ActualHeight; _aw = canvasBar.ActualWidth; var timeA = trgDate; var timeB = trgDate.AddDays(.9999999); var isHere = Environment.MachineName.Equals(pc, StringComparison.OrdinalIgnoreCase); SortedList <DateTime, int> eois; if (isHere) { var localEvLog = EvLogHelper.GetAllUpDnEvents(timeA, timeB); var dbaseEvLog = DbLogHelper.GetAllUpDnEvents(timeA, timeB, pc); eois = localEvLog.Count > dbaseEvLog.Count ? localEvLog : dbaseEvLog; // Jan 2020: whoever has more events wins! } else { eois = DbLogHelper.GetAllUpDnEvents(timeA, timeB, pc); } if (trgDate == DateTime.Today && isHere) { eois.Add(DateTime.Now, 2); // == ((int)EvOfIntFlag.ScreenSaverrUp) } if (eois.Count < 1) { tbSummary.Text = $"{trgDate,16:ddd, MMM dd yyyy} no activities logged on this date."; } else { var eoi0 = eois.FirstOrDefault(); var prevEoiF = eoi0.Value == (int)EvOfIntFlag.ScreenSaverrDn ? EvOfIntFlag.ScreenSaverrUp : eoi0.Value == (int)EvOfIntFlag.BootAndWakeUps ? EvOfIntFlag.ShutAndSleepDn : EvOfIntFlag.Day1stAmbiguos; foreach (var eoi in eois) { addWkTimeSegment(timeA, eoi.Key, prevEoiF, (EvOfIntFlag)eoi.Value, pcClr, ref ts); timeA = eoi.Key; prevEoiF = (EvOfIntFlag)eoi.Value; } var lastScvrUp = (eois.Any(r => r.Value == (int)EvOfIntFlag.ScreenSaverrUp || r.Value == (int)EvOfIntFlag.ShutAndSleepDn) ? eois.Where(r => r.Value == (int)EvOfIntFlag.ScreenSaverrUp || r.Value == (int)EvOfIntFlag.ShutAndSleepDn).Last() : eois.Last()).Key; var finalEvent = eois.Last().Key; ts.TotalDaysUp = (lastScvrUp < finalEvent ? lastScvrUp : finalEvent) - eois.First().Key; tbSummary.Text = $"{trgDate,16:ddd, MMM dd yyyy} {ts.TotalDaysUp,5:h\\:mm} ({ts.WorkedFor:h\\:mm}) "; } tbSummary.Foreground = (trgDate.DayOfWeek == DayOfWeek.Saturday || trgDate.DayOfWeek == DayOfWeek.Sunday) ? cWEd : cWDd; gridvroot.Background = (trgDate.DayOfWeek == DayOfWeek.Saturday || trgDate.DayOfWeek == DayOfWeek.Sunday) ? cPnk : cBlk; } catch (Exception ex) { ex.Pop(); } finally { Trace.WriteLine($" ==> { tbSummary.Text} "); } }