员工时钟计算

Employee Time Clock Calculation

我希望有人能帮我找到一个最佳解决方案。我有一个时间日志列表。它包含每个员工每天每次打卡的数据时间条目。

我正在尝试想出一个好的解决方案来计算每天的工作时间。一名员工每次签到和签退之间的时间间隔。

最后的结果一定要给我以下

例如 时钟输入:06:00 计时结束:10:00 打卡时间:10:15

休息时间 = 00:15

等等。

我尽量避免使用太多 for 循环/foreach 循环。

这是一段代表时间日志列表的示例代码。类型是。 I = 时钟输入,O = 时钟输出。每个班次都有块开始时间和块结束时间。

var blockStart = new TimeSpan(0,6,0,0,0);
var blockEnd = new TimeSpan(0,17,0,0);

var listOfTimeLogs = new List<TimeLog>()
        {
            new TimeLog() {EntryDateTime = new DateTime(2016,05,20,6,0,0),Type = "I"},
            new TimeLog() {EntryDateTime = new DateTime(2016,05,20,10,0,0),Type = "O"},
            new TimeLog() {EntryDateTime = new DateTime(2016,05,20,10,15,0),Type = "I"},
            new TimeLog() {EntryDateTime = new DateTime(2016,05,20,12,0,0),Type = "O"},
            new TimeLog() {EntryDateTime = new DateTime(2016,05,20,12,30,0),Type = "I"},
            new TimeLog() {EntryDateTime = new DateTime(2016,05,20,15,0,0),Type = "O"},
            new TimeLog() {EntryDateTime = new DateTime(2016,05,20,15,15,0),Type = "I"},
            new TimeLog() {EntryDateTime = new DateTime(2016,05,20,18,00,0),Type = "O"}
        };

希望这是有道理的。任何帮助将不胜感激。 谢谢

计算机是用来做循环的。

这里是 sample 我将如何处理这个问题。

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;

namespace TimeClock
{
    class Program
    {
        static void Main()
        {
            var blockStart = new TimeSpan(0, 6, 0, 0);
            var blockEnd = new TimeSpan(0, 17, 0, 0);

            var listOfTimeLogs = new List<TimeLog>
            {
                new TimeLog {EntryDateTime = new DateTime(2016,05,20,6,0,0),EntryType = EntryTypes.In},
                new TimeLog {EntryDateTime = new DateTime(2016,05,20,10,0,0),EntryType = EntryTypes.Out},
                new TimeLog {EntryDateTime = new DateTime(2016,05,20,10,15,0),EntryType = EntryTypes.In},
                new TimeLog {EntryDateTime = new DateTime(2016,05,20,12,0,0),EntryType = EntryTypes.Out},
                new TimeLog {EntryDateTime = new DateTime(2016,05,20,12,30,0),EntryType = EntryTypes.In},
                new TimeLog {EntryDateTime = new DateTime(2016,05,20,15,0,0),EntryType = EntryTypes.Out},
                new TimeLog {EntryDateTime = new DateTime(2016,05,20,15,15,0),EntryType = EntryTypes.In},
                new TimeLog {EntryDateTime = new DateTime(2016,05,20,18,00,0),EntryType = EntryTypes.Out}
            };


            // You are going to have have for / for each unless you use Linq

            // fist I would count clock in's versus the out's
            var totalIn = listOfTimeLogs.Count(e => e.EntryType == EntryTypes.In);
            var totalOut = listOfTimeLogs.Count() - totalIn;

            // check if we have in the number of time entries
            if (totalIn > totalOut)
            {
                Console.WriteLine("Employee didn't clock out");
            }

            // as I was coding this sample program, i thought of another way to store the time
            // I would store them in blocks - we have to loop
            var timeBlocks = new List<TimeBlock>();
            for (var x = 0; x < listOfTimeLogs.Count; x += 2)
            {
                // create a new WORKING block based on the in/out time entries
                timeBlocks.Add(new TimeBlock
                {
                    BlockType = BlockTypes.Working,
                    In = listOfTimeLogs[x],
                    Out = listOfTimeLogs[x + 1]
                });

                // create a BREAK block based on gaps
                // check if the next entry in a clock in
                var breakOut = x + 2;
                if (breakOut < listOfTimeLogs.Count)
                {
                    var breakIn = x + 1;
                    // create a new BREAK block
                    timeBlocks.Add(new TimeBlock
                    {
                        BlockType = BlockTypes.Break,
                        In = listOfTimeLogs[breakIn],
                        Out = listOfTimeLogs[breakOut]
                    });
                }
            }

            var breakCount = 0;
            // here is a loop for displaying detail
            foreach (var block in timeBlocks)
            {
                var lineTitle = block.BlockType.ToString();
                // this is me trying to be fancy
                if (block.BlockType == BlockTypes.Break)
                {
                    if (block.IsBreak())
                    {
                        lineTitle = $"Break #{++breakCount}";
                    }
                    else
                    {
                        lineTitle = "Lunch";
                    }
                }
                Console.WriteLine($" {lineTitle,-10} {block}  ===  Length: {block.Duration.ToString(@"hh\:mm")}");
            }

            // calculating total time for each block type
            var workingTime = timeBlocks.Where(b => b.BlockType == BlockTypes.Working)
                    .Aggregate(new TimeSpan(0), (p, v) => p.Add(v.Duration));

            var breakTime = timeBlocks.Where(b => b.BlockType == BlockTypes.Break)
                    .Aggregate(new TimeSpan(0), (p, v) => p.Add(v.Duration));


            Console.WriteLine($"\nTotal Working Hours: {workingTime.ToString(@"hh\:mm")}");
            Console.WriteLine($"   Total Break Time: {breakTime.ToString(@"hh\:mm")}");

            Console.ReadLine();
        }
    }
}

TimeBlock.cs

using System;

namespace TimeClock
{
    public enum BlockTypes
    {
        Working,
        Break
    }

    public class TimeBlock
    {
        public BlockTypes BlockType;
        public TimeLog In;
        public TimeLog Out;

        public TimeSpan Duration
        {
            get
            {
                // TODO: Need error checking
                return Out.EntryDateTime.Subtract(In.EntryDateTime);
            }
        }

        public override string ToString()
        {
            return $"In: {In.EntryDateTime:HH:mm} - Out: {Out.EntryDateTime:HH:mm}";
        }

    }

    // a little extension class
    public static class Extensions
    {
        public static bool IsBreak(this TimeBlock block)
        {
            // if the length of the break period is less than 19 minutes
            // we will consider it a break, the person could have clock IN late
            return block.Duration.TotalMinutes < 19 ? true : false;

        }

    }

}

TimeLog.cs

using System;

namespace TimeClock
{
    public class TimeLog
    {
        public DateTime EntryDateTime;
        public EntryTypes EntryType;
    }
}

EntryTypes.cs

namespace TimeClock
{
    public enum EntryTypes
    {
        In,
        Out
    }
}