//adjusts start/endtime such that a possible overtime can be billed public void updateFullDay(DateTime day, WorktimeStatistics wtstats, DateTime end) { if (!WorktrackerConnectInternal()) { return; } var workEntries = worktracker.QueryWorkEntries(currentUser, day.Date, new TimeSpan(1, 0, 0, 0)); if (workEntries.Count == 0) { throw new Exception("No Workentry found"); } var workEntry = workEntries[0]; var trueEnd = (workEntry.StopTime != default(DateTime) && workEntry.IsComplete) ? workEntry.StopTime : end; Tuple <DateTime, DateTime, TimeSpan> newTimes = calcAdaptedStartEndTimes(day, wtstats, trueEnd); workEntry.BreakDuration = newTimes.Item3; workEntry.StartTime = newTimes.Item1; workEntry.StopTime = newTimes.Item2; workEntry.IsComplete = true; worktracker.UpdateWorkEntry(workEntry); }
//This method is just for testing as I had troubles with invoking the method with out-params private Tuple <WorktimeStatistics, Dictionary <string, TimeSpan> > calculateOvertimeUndertimeForTesting(WorktimeStatistics originalWts, Dictionary <string, TimeSpan> originalOvertimes) { WorktimeStatistics newWts = null; Dictionary <string, TimeSpan> overtimes = null; calculateOvertimeUndertime(originalWts, originalOvertimes, out newWts, out overtimes); return(new Tuple <WorktimeStatistics, Dictionary <string, TimeSpan> >(newWts, overtimes)); }
public WorktimeStatistics considerOvertimeUndertime(WorktimeStatistics originalWts) { var newWts = new WorktimeStatistics(); var newOvertimes = new Dictionary <string, TimeSpan>(); calculateOvertimeUndertime(originalWts, Storage.getOvertimes(), out newWts, out newOvertimes); Storage.updateOvertimes(newOvertimes); return(newWts); }
public WorktimeStatistics(WorktimeStatistics wts) { projectTimes = wts.projectTimes.ToDictionary(e => e.Key, e => e.Value); relativeProjectTimes = wts.relativeProjectTimes.ToDictionary(e => e.Key, e => e.Value); projectComments = wts.projectComments.ToDictionary(e => e.Key, e => e.Value.ToDictionary(e1 => e1.Key, e1 => e1.Value)); totalTime = wts.totalTime; totalProjectTime = wts.totalProjectTime; totalWorktime = wts.totalWorktime; totalPausetime = wts.totalPausetime; totalWorkbreaktime = wts.totalWorkbreaktime; totalPrivateTime = wts.totalPrivateTime; }
public void updateProjectEntries(DateTime day, WorktimeStatistics wtstats) { if (!WorktrackerConnectInternal()) { return; } updateWtProjects(); var wtprojects = joinToWtProjects(wtstats); var quantizedProjects = quantizeProjectsTo5(wtprojects); addProjectEntriesToWorktracker(day, quantizedProjects); }
public Dictionary <string, TimeSpan> calcAllProjectimeAsOvertime(WorktimeStatistics wts, Dictionary <string, TimeSpan> originalOvertimes) { var newOvertimes = originalOvertimes.ToDictionary(e => e.Key, e => e.Value); //clone foreach (var pj in wts.projectTimes) { if (!newOvertimes.ContainsKey(pj.Key)) { newOvertimes[pj.Key] = new TimeSpan(0, 0, 0); } newOvertimes[pj.Key] += pj.Value; } return(newOvertimes); }
private Dictionary <Project, float> joinToWtProjects(WorktimeStatistics wtstats) { var wtprojects = new Dictionary <Project, float>(); foreach (var pjs in wtstats.relativeProjectTimes) { var wtprojectname = getWTProjectname(pjs.Key); var wtproject = projects.FirstOrDefault(x => x.Value.UniqueName == wtprojectname).Value; //todo auslagern if (wtproject == null) { throw new Exception($"WtProject name {wtprojectname} not found in Worktracker unique project Names"); } if (!wtprojects.ContainsKey(wtproject)) { wtprojects[wtproject] = 0; } wtprojects[wtproject] += pjs.Value; } return(wtprojects); }
public Tuple <DateTime, DateTime, TimeSpan> calcAdaptedStartEndTimes(DateTime day, WorktimeStatistics wtstats, DateTime origEnd) { var newPause = wtstats.totalPausetime; var tmpEnd = ((origEnd.Date == day.Date && origEnd.Hour > 22) || origEnd.Date == day.Add(new TimeSpan(24, 0, 0)).Date) ? (day.Date + new TimeSpan(22, 0, 0)) : origEnd; var tmpStart = (tmpEnd - wtstats.totalTime); //if start is after 12 o'clock, pretend we started to work at 10 if (tmpStart.TimeOfDay > new TimeSpan(12, 0, 0)) { var t = tmpStart.TimeOfDay - new TimeSpan(10, 0, 0); tmpStart -= t; tmpEnd -= t; } //if we begin before 6 o'clock, pretend that we started at least at 6 if (tmpStart.TimeOfDay < new TimeSpan(6, 0, 0)) { var t = new TimeSpan(6, 0, 0) - tmpStart.TimeOfDay; tmpStart += t; tmpEnd += t; } var newStart = tmpEnd - wtstats.totalTime; var newEnd = tmpEnd; //if we are finishing the current day, finish now because otherwise value will be overridden by alarm checkout //However, it must not start before 6 o'clock in any case if (day.Date == DateTime.Now.Date && tmpEnd > DateTime.Now) { var t = tmpEnd - DateTime.Now; if ((tmpStart - t).TimeOfDay < new TimeSpan(6, 0, 0)) { var t2 = new TimeSpan(6, 0, 0) - (tmpStart - t).TimeOfDay; t -= t2; } tmpStart -= t; tmpEnd -= t; } //if pause time is too short, shift start and make pause 40mins if (newPause < new TimeSpan(0, 40, 0)) { newStart -= new TimeSpan(0, 40, 0) - wtstats.totalPausetime; newPause = new TimeSpan(0, 40, 0); } return(new Tuple <DateTime, DateTime, TimeSpan>(newStart, newEnd, newPause)); }
public Tuple <DateTime, DateTime, TimeSpan> calcAdaptedStartEndTimes(DateTime day, WorktimeStatistics wtstats, DateTime origEnd) { throw new Exception("Worktracker not supported in current build"); }
public void updateFullDay(DateTime day, WorktimeStatistics wtstats, DateTime end) { throw new Exception("Worktracker not supported in current build"); }
public void updateProjectEntries(DateTime day, WorktimeStatistics wtstats) { throw new Exception("Worktracker not supported in current build"); }
private WorktimeStatistics generateStatistics(List <WorktimeRecord> worktimeRecords) { //TODO write current desktop to storage var currentStats = new WorktimeStatistics(); foreach (var wtr in worktimeRecords) { if (String.IsNullOrEmpty(wtr.ProjectName) || wtr.ProjectName.Contains("[unknown")) { continue; //that happens e.g. for Init project rows } var currentInterval = TimeSpan.FromSeconds((wtr.End - wtr.Start).TotalSeconds); if (wtr.ProjectName == ProjectChangeHandler.PROJECT_WORKTIMEBREAK) { currentStats.totalWorkbreaktime += currentInterval; currentStats.totalWorktime += currentInterval; } else if (wtr.ProjectName == ProjectChangeHandler.PROJECT_PAUSE) { currentStats.totalPausetime += currentInterval; } else if (wtr.ProjectName == ProjectChangeHandler.PROJECT_PRIVAT) { currentStats.totalPrivateTime += currentInterval; } else //normal project { if (!currentStats.projectTimes.ContainsKey(wtr.ProjectName)) { currentStats.projectTimes[wtr.ProjectName] = new TimeSpan(0, 0, 0); } currentStats.projectTimes[wtr.ProjectName] += currentInterval; currentStats.totalProjectTime += currentInterval; currentStats.totalWorktime += currentInterval; } currentStats.totalTime += currentInterval; if (!currentStats.projectComments.ContainsKey(wtr.ProjectName)) { currentStats.projectComments.Add(wtr.ProjectName, new Dictionary <string, TimeSpan>()); } var comment = !String.IsNullOrEmpty(wtr.Comment) ? wtr.Comment : "General"; if (!currentStats.projectComments[wtr.ProjectName].ContainsKey(comment)) { currentStats.projectComments[wtr.ProjectName].Add(comment, new TimeSpan()); } var newSum = currentStats.projectComments[wtr.ProjectName][comment] + currentInterval; currentStats.projectComments[wtr.ProjectName][comment] = newSum; } foreach (var project in currentStats.projectTimes) { currentStats.relativeProjectTimes[project.Key] = (float)(project.Value.TotalSeconds / currentStats.totalProjectTime.TotalSeconds) * 100; } //currentStats.totalTime.Milliseconds = 0; return(currentStats); }
public void takeAllProjectimeAsOvertime(WorktimeStatistics wts) { var newOvertimes = calcAllProjectimeAsOvertime(wts, Storage.getOvertimes()); Storage.updateOvertimes(newOvertimes); }
public void calculateOvertimeUndertime(WorktimeStatistics originalWts, Dictionary <string, TimeSpan> originalOvertimes, out WorktimeStatistics newWts, out Dictionary <string, TimeSpan> newOvertimes) { newWts = new WorktimeStatistics(originalWts); newOvertimes = originalOvertimes.ToDictionary(e => e.Key, e => e.Value); //clone if (originalWts.totalWorktime > maxWorktime) //we worked overtime { TimeSpan diff = originalWts.totalWorktime - maxWorktime; var projectIndex = 0; while (diff > new TimeSpan(0, 0, 0)) { var project = originalWts.projectTimes.Keys.ToList().ElementAt(projectIndex); var time = originalWts.projectTimes.Values.ToList().ElementAt(projectIndex); var timeToSubtract = new TimeSpan(0, 0, 0); if (time <= diff) //whole project time is consumed { if (!newOvertimes.ContainsKey(project)) { newOvertimes[project] = new TimeSpan(0, 0, 0); } newOvertimes[project] += time; newWts.projectTimes[project] = new TimeSpan(0, 0, 0); timeToSubtract = time; diff -= time; } else //project time is only partially consumed { if (!newOvertimes.ContainsKey(project)) { newOvertimes[project] = new TimeSpan(0, 0, 0); } newOvertimes[project] += diff; newWts.projectTimes[project] -= diff; timeToSubtract = diff; diff = new TimeSpan(0, 0, 0); } newWts.totalTime -= timeToSubtract; newWts.totalProjectTime -= timeToSubtract; newWts.totalWorktime -= timeToSubtract; projectIndex++; } } else //we worked less time than maxTime { TimeSpan diff = maxWorktime - originalWts.totalWorktime; var ovtIndex = 0; while (diff > new TimeSpan(0, 0, 0) && sumTimespans(originalOvertimes.Values.ToList()) > new TimeSpan(0, 0, 0)) { var project = originalOvertimes.Keys.ToList().ElementAt(ovtIndex); var time = originalOvertimes.Values.ToList().ElementAt(ovtIndex); var timeToAdd = new TimeSpan(0, 0, 0); if (diff > time) //a whole overtime is consumed { timeToAdd = time; newOvertimes[project] = new TimeSpan(0, 0, 0); if (!newWts.projectTimes.ContainsKey(project)) { newWts.projectTimes[project] = new TimeSpan(0, 0, 0); } newWts.projectTimes[project] += time; diff -= time; originalOvertimes[project] -= time; } else //an overtime is partially consumed { timeToAdd = diff; newOvertimes[project] -= diff; if (!newWts.projectTimes.ContainsKey(project)) { newWts.projectTimes[project] = new TimeSpan(0, 0, 0); } newWts.projectTimes[project] += diff; diff = new TimeSpan(0, 0, 0); } newWts.totalTime += timeToAdd; newWts.totalProjectTime += timeToAdd; newWts.totalWorktime += timeToAdd; ovtIndex++; } } foreach (var project in newWts.projectTimes) { newWts.relativeProjectTimes[project.Key] = (float)(project.Value.TotalSeconds / newWts.totalProjectTime.TotalSeconds) * 100; } }
//------------------------------------------------ //------------------------------------------------ private void AnalyzeWorktimes() { if (WorktimeAnalyzer == null) { return; } try { var projectStatistics = WorktimeAnalyzer.AnalyzeWorkday(Form.dateTimePicker1.Value); WorktimeStatistics projectStatisticsReal = null; if (Form.flagConsiderOvertime.Checked) { Dictionary <string, TimeSpan> newOvertimes = null; WorktimeAnalyzer.calculateOvertimeUndertime(projectStatistics, storage.getOvertimes(), out projectStatisticsReal, out newOvertimes); } else { projectStatisticsReal = projectStatistics; } Form.currentOvertime.Text = WorktimeAnalyzer.sumTimespans(storage.getOvertimes().Values.ToList()).FormatForOvertime(); Form.ProjectTimesSummary.Series.Clear(); Series series = new Series { Name = "projects", IsVisibleInLegend = false, ChartType = SeriesChartType.Column }; Form.ProjectTimesSummary.Series.Add(series); foreach (var project in projectStatisticsReal.projectTimes) { series.Points.Add(project.Value.TotalMinutes); var p = series.Points.Last(); p.AxisLabel = project.Key; p.Label = Math.Round(projectStatisticsReal.relativeProjectTimes[project.Key]).ToString() + "%"; if (projectStatisticsReal.projectComments.ContainsKey(project.Key)) //can happen for overtime, probably not the most appropriate solution { p.ToolTip = "Total: " + Math.Round(project.Value.TotalHours, 1) + "h\n" + String.Join("\n", projectStatisticsReal.projectComments[project.Key] .OrderByDescending(s => s.Value.Ticks) //order by comment timespan-sum .Select(s => Math.Round(s.Value.TotalHours, 1) + "h: " + s.Key) ); } } Form.ProjectTimesSummary.ChartAreas[0].AxisX.MajorGrid.LineWidth = 0; Form.ProjectTimesSummary.ChartAreas[0].AxisY.MajorGrid.LineWidth = 0; Form.ProjectTimesSummary.ChartAreas[0].BackColor = System.Drawing.SystemColors.Control; Form.ProjectTimesSummary.ChartAreas[0].RecalculateAxesScale(); Form.ProjectTimesSummary.Invalidate(); Form.ProjectTimesSummary.Visible = true; Form.totalTime.Text = projectStatisticsReal.totalTime.ToString(@"hh\:mm\:ss"); Form.PrivateTime.Text = projectStatisticsReal.totalPrivateTime.ToString(@"hh\:mm\:ss"); Form.PauseTime.Text = projectStatisticsReal.totalPausetime.ToString(@"hh\:mm\:ss"); Form.Worktime.Text = projectStatisticsReal.totalWorktime.ToString(@"hh\:mm\:ss"); Form.ProjectTime.Text = projectStatisticsReal.totalProjectTime.ToString(@"hh\:mm\:ss"); Form.Workbreaktime.Text = projectStatisticsReal.totalWorkbreaktime.ToString(@"hh\:mm\:ss"); } catch (Exception ex) { MessageBox.Show(ex.ToString()); } }