首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将打卡时间列表转换为按小时工作的时间(以C#为单位

将打卡时间列表转换为按小时工作的时间(以C#为单位
EN

Stack Overflow用户
提问于 2017-03-18 06:27:18
回答 1查看 102关注 0票数 1

我有一个对象列表,详细说明了工人的时钟打卡,如下所示:

代码语言:javascript
复制
Person  Time     Action
Cindy   07:00    clockin
Jim     08:12    clockin
Cindy   11:15    startlunch
Cindy   12:12    endlunch
Jim     12:30    startlunch
Jim     12:55    endlunch
Cindy   15:30    clockout
Jim     17:00    clockout

当然,真正的数据是成百上千的人,而且是按部门等分类的。

他们希望我创建一份报告,显示一天中每小时的工作量。最终结果应该如下所示:

代码语言:javascript
复制
Time   Worked
7-8      1
8-9      1.8
9-10     2
10-11    2
11-12    1.25
12-1     1.3
etc.

作为一个最基本的步骤,我已经将一系列的冲压转换成了一个WorkRecords列表,它看起来像这样:

代码语言:javascript
复制
Person     In      Out
Cindy      07:00  11:15 
Jim        08:22  12:30
Cindy      12:12  15:30
Jim        12:55  17:00

我在考虑循环所有的小时并测试每个WorkRecord,如果它包含在给定的小时内的时间,但这似乎很麻烦。

有没有一种更优雅的方法可以使用lambda或linq表达式将我的数据重新组织到最终产品中?它可以从原始数据开始,也可以从内部开始。感谢您对此谜题的研究。

EN

回答 1

Stack Overflow用户

发布于 2017-03-18 11:12:58

这是我使用LINQ的尝试。

我假设您的WorkRecord是这样的。

代码语言:javascript
复制
    public  class WorkRecord
    {
        public readonly String name;
        public readonly DateTime StarTime;
        public readonly DateTime EndTime;

        public WorkRecord(string name, DateTime starTime, DateTime endTime)
        {
            this.name = name;
            StarTime = starTime;
            EndTime = endTime;
        }

        public WorkRecord(string name, string starTime, string endTime)
        {
            this.name = name;
            StarTime = DateTime.ParseExact(starTime, "HH:mm", null);
            EndTime = DateTime.ParseExact(endTime, "HH:mm", null);
        }
    }

目前还不清楚它们是否已经预先过滤了一天。我将尝试涵盖这两种情况(但仍然过于简单)

代码语言:javascript
复制
    public  class DayStats
    {
        public readonly int[] TotalMinutes = new int[24];

        public void AddWorkRecord(WorkRecord record)
        {
            // Note: this method doesn't handle case when EndTime is next day
            // handle "middle" hours, they are all full
            for (int hour = record.StarTime.Hour + 1; hour < record.EndTime.Hour; hour++)
            {
                TotalMinutes[hour] += 60;
            }
            // handle first and last hours that might be not full
            if (record.StarTime.Hour == record.EndTime.Hour)
            {
                TotalMinutes[record.StarTime.Hour] += record.EndTime.Minute - record.StarTime.Minute;
            }
            else
            {
                TotalMinutes[record.StarTime.Hour] += 60 - record.StarTime.Minute;
                TotalMinutes[record.EndTime.Hour] += record.EndTime.Minute;
            }
        }

        public string AsPrettyString()
        {
            return string.Join("\n", TotalMinutes
                .Select((totalMinutes, hour) => string.Format("{0}-{1} {2}", hour, hour + 1, totalMinutes)));
        }
    }

    public class TimeCardAggregate
    {
        private readonly Dictionary<DateTime, DayStats> _days = new Dictionary<DateTime, DayStats>();

        public void AddWorkRecord(WorkRecord record)
        {
            // Note: this method doesn't handle case when EndTime is next day
            var date = record.StarTime.Date;
            DayStats dayStats;
            if (!_days.TryGetValue(date, out dayStats))
            {
                dayStats = new DayStats();
                _days.Add(date, dayStats);
            }
            dayStats.AddWorkRecord(record);
        }

        public List<KeyValuePair<DateTime, DayStats>> GetTimecard()
        {
            return _days.ToList().OrderBy(kv => kv.Key).ToList();
        }
    }

DayStats表示单日的聚合结果。TimeCardAggregate是几天的结果。看看如何使用它们:

代码语言:javascript
复制
    static void Main(string[] args)
    {
        List<WorkRecord> records = new List<WorkRecord>
        {
            new WorkRecord("Cindy", "07:00", "11:15"),
            new WorkRecord("Jim", "08:22", "12:30"),
            new WorkRecord("Jim", "12:12", "15:30"),
            new WorkRecord("Cindy", "12:55", "17:00")
        };

        var dayStats = records.Aggregate(new DayStats(), (ds, wr) =>
        {
            ds.AddWorkRecord(wr);
            return ds;
        });

        Console.WriteLine(dayStats.AsPrettyString());



        List<WorkRecord> recordsForTwoDays = new List<WorkRecord>();
        recordsForTwoDays.AddRange(records);
        // just copy the data for the next day
        recordsForTwoDays.AddRange(records.Select(wr => new WorkRecord(wr.name, wr.StarTime.AddDays(1), wr.StarTime.AddDays(1))));
        var timecard = recordsForTwoDays.Aggregate(new TimeCardAggregate(), (ds, wr) =>
        {
            ds.AddWorkRecord(wr);
            return ds;
        });
        Console.WriteLine("\n\n");


        Console.WriteLine(string.Join("\n-------------\n", timecard.GetTimecard().Select(kv =>
        {
            return kv.Key.ToShortDateString() + ":\n" + dayStats.AsPrettyString();
        })));
    }

还要注意的是,这两种AddWorkRecord实现都很幼稚,不能处理有人通宵工作并在几天内产生记录的情况。不过,修复它并不是很难。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42868029

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档