将DateTime条目列表转换为自定义摘要列表

时间:2013-08-14 12:56:51

标签: c# linq-to-sql

Punches = new List<TimeClock>(); // Populated from database ...

现有清单:

[Employee] - [DateTime] - [Action]
x1 - y1 - in
x2 - y2 - in
x1 - y3 - out
x3 - y4 - in
x1 - y5 - in
x3 - y6 - out
x2 - y7 - out
x1 - y8 - out
x2 - y9 - in
x2 - y10 - out

所需的清单格式:

[Employee] - [Start] - [End] - [Hours]
x1 - y1 - y3 - z1
x1 - y5 - y8 - z2
x2 - y2 - y7 - z3
x2 - y9 - y10 - z4
x3 - y4 - y6 - z5

我正在尝试采用List员工/时间/行动并将其展平为员工/开始/结束/持续时间的摘要列表,每个员工每个相应的进/出时间有1行。< / p>

我不确定如何创建新列表,或者我是否应该将其称为List?我来自PHP,我会使用Array来构建员工的摘要,但我不确定如何在C#中执行此操作。

下面的代码是我如何设法从主List获得每个Employee工作小时数的总结,我想我可以使用类似的结构/循环来制作摘要列表但是我不确定到底是怎么回事,我也尝试使用struct来定义列表......有人指出我正确的方向!

    /// <summary>
    /// Populates HoursWorked List
    /// </summary>
    public void PopulateHoursWorkedList()
    {
        // Get list of time clock punches
        PayPeriodPunches = new List<TimeClock>();

        if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(new DependencyObject()))
            using (var db = new Database())
            {
                // Load with Employee
                DataLoadOptions dlo = new DataLoadOptions();
                dlo.LoadWith<TimeClock>(tc => tc.Employee);
                db.LoadOptions = dlo;

                PayPeriodPunches = db.TimeClockPunches
                    .Where(cp => cp.ClockPunchDateTime >= PayPeriodSelected.BeginDateTime
                                && cp.ClockPunchDateTime <= PayPeriodSelected.EndDateTime)
                    .OrderBy(cp => cp.ClockPunchDateTime)
                    .ToList();
            }

        // Get unique list of employees and sum of hours worked
        HoursWorkedList = new List<EmployeeHoursWorked>();
        foreach (TimeClock tcp in PayPeriodPunches)
        {
            if (!HoursWorkedList.Exists(e => e.Employee == tcp.Employee))
            {
                EmployeeHoursWorked ehw = new EmployeeHoursWorked();
                ehw.Employee = tcp.Employee;
                HoursWorkedList.Add(ehw);
            }
        }

        foreach (EmployeeHoursWorked ehw in HoursWorkedList.ToList())
        {
            Employee e = ehw.Employee;
            // This employees punches
            List<TimeClock> thisEmpPunches = PayPeriodPunches
                .Where(pp => pp.Employee == e)
                .OrderBy(pp => pp.ClockPunchDateTime)
                .ToList();

            bool hasClockedIn = false;
            bool hasClockedOut = false;
            int i = 0;
            DateTime dts = new DateTime();
            DateTime dte = new DateTime();
            TimeSpan dur = new TimeSpan();

            foreach (TimeClock tcp in thisEmpPunches)
            {
                if (tcp.ClockAction == ClockAction.In)
                {
                    dts = tcp.ClockPunchDateTime;
                    hasClockedIn = true;
                    i = 1;
                }

                if (tcp.ClockAction == ClockAction.Out)
                {
                    dte = tcp.ClockPunchDateTime;

                    // Was clocked In: Use previous clock-in time
                    if (i == 1)
                    {
                        dur = dte - dts;
                    }
                    else
                    {
                        // Not clocked in, never clocked in, assume clocked in since beginning of PP
                        if (!hasClockedIn)
                        {
                            dts = PayPeriodSelected.BeginDateTime;
                            dur = dte - dts;
                        }
                    }

                    // Update employee hours worked duration
                    int index = HoursWorkedList.FindIndex(z => z.Employee == e);
                    EmployeeHoursWorked tmp = HoursWorkedList[index];
                    tmp.HoursWorked += dur;
                    HoursWorkedList[index] = tmp;

                    hasClockedOut = true;
                    i = 2;
                }

            }

            if (i == 1)
            {
                // Employee never clocked out, assume end of PP (or now if sooner)
                if (DateTime.Now < PayPeriodSelected.EndDateTime)
                {
                    dte = DateTime.Now;
                }
                else
                {
                    dte = PayPeriodSelected.EndDateTime;
                }

                // Update employee hours worked duration
                dur = dte - dts;
                int index = HoursWorkedList.FindIndex(z => z.Employee == e);
                EmployeeHoursWorked tmp = HoursWorkedList[index];
                tmp.HoursWorked += dur;
                HoursWorkedList[index] = tmp;
            }

        }

    }

2 个答案:

答案 0 :(得分:0)

好的,谢谢橡皮鸭。毕竟能够使用循环,只需要大声思考......

请注意包含以下代码块的部分:

EmployeeClockSummary ecs = new EmployeeClockSummary();
ecs.Employee = e;
ecs.ClockInTime = dts;
ecs.ClockOutTime = dte;
HoursSummaryList.Add(ecs);

使用:

/// <summary>
/// Populates HoursSummary List
/// </summary>
public void PopulateHoursSummaryList()
{
    HoursSummaryList = new List<EmployeeClockSummary>();

    // Get list of time clock punches
    PayPeriodPunches = new List<TimeClock>();

    if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(new DependencyObject()))
    using (var db = new Database())
    {
        // Load with Employee
        DataLoadOptions dlo = new DataLoadOptions();
        dlo.LoadWith<TimeClock>(tc => tc.Employee);
        db.LoadOptions = dlo;

        PayPeriodPunches = db.TimeClockPunches
                .Where(cp => cp.ClockPunchDateTime >= PayPeriodSelected.BeginDateTime
                            && cp.ClockPunchDateTime <= PayPeriodSelected.EndDateTime)
                .OrderBy(cp => cp.ClockPunchDateTime)
                .ToList();
    }

    // Get unique list of employees and sum of hours worked
    HoursWorkedList = new List<EmployeeHoursWorked>();
    foreach (TimeClock tcp in PayPeriodPunches)
    {
        if (!HoursWorkedList.Exists(e => e.Employee == tcp.Employee))
        {
            EmployeeHoursWorked ehw = new EmployeeHoursWorked();
            ehw.Employee = tcp.Employee;
            HoursWorkedList.Add(ehw);
        }
    }

    foreach (EmployeeHoursWorked ehw in HoursWorkedList.ToList())
    {
        Employee e = ehw.Employee;
        // This employees punches
        List<TimeClock> thisEmpPunches = PayPeriodPunches
            .Where(pp => pp.Employee == e)
            .OrderBy(pp => pp.ClockPunchDateTime)
            .ToList();

        bool hasClockedIn = false;
        bool hasClockedOut = false;
        int i = 0;
        DateTime dts = new DateTime();
        DateTime dte = new DateTime();
        TimeSpan dur = new TimeSpan();

        foreach (TimeClock tcp in thisEmpPunches)
        {
            if (tcp.ClockAction == ClockAction.In)
            {
                dts = tcp.ClockPunchDateTime;
                hasClockedIn = true;
                i = 1;
            }

            if (tcp.ClockAction == ClockAction.Out)
            {
                dte = tcp.ClockPunchDateTime;

                // Was clocked In: Use previous clock-in time
                if (i == 1)
                {
                    dur = dte - dts;

                    EmployeeClockSummary ecs = new EmployeeClockSummary();
                    ecs.Employee = e;
                    ecs.ClockInTime = dts;
                    ecs.ClockOutTime = dte;
                    HoursSummaryList.Add(ecs);
                }
                else
                {
                    // Not clocked in, never clocked in, assume clocked in since beginning of PP
                    if (!hasClockedIn)
                    {
                        dts = PayPeriodSelected.BeginDateTime;
                        dur = dte - dts;

                        EmployeeClockSummary ecs = new EmployeeClockSummary();
                        ecs.Employee = e;
                        ecs.ClockInTime = dts;
                        ecs.ClockOutTime = dte;
                        HoursSummaryList.Add(ecs);
                    }
                }

                // Update employee hours worked duration
                int index = HoursWorkedList.FindIndex(z => z.Employee == e);
                EmployeeHoursWorked tmp = HoursWorkedList[index];
                tmp.HoursWorked += dur;
                HoursWorkedList[index] = tmp;

                hasClockedOut = true;
                i = 2;
            }
        }

        if (i == 1)
        {
            // Employee never clocked out, assume end of PP (or now if sooner)
            if (DateTime.Now < PayPeriodSelected.EndDateTime)
            {
                dte = DateTime.Now;
            }
            else
            {
                dte = PayPeriodSelected.EndDateTime;
            }

            EmployeeClockSummary ecs = new EmployeeClockSummary();
            ecs.Employee = e;
            ecs.ClockInTime = dts;
            ecs.ClockOutTime = dte;
            HoursSummaryList.Add(ecs);

            // Update employee hours worked duration
            dur = dte - dts;
            int index = HoursWorkedList.FindIndex(z => z.Employee == e);
            EmployeeHoursWorked tmp = HoursWorkedList[index];
            tmp.HoursWorked += dur;
            HoursWorkedList[index] = tmp;
        }

        if (HoursSummaryList.Any())
        {
        }
    }
}

答案 1 :(得分:0)

因此,只需修改LINQ查询以使用GroupBy,我就可以轻松制作扁平列表:

foreach (var empInOuts in PayPeriodPunches
    .OrderBy(x => x.ClockPunchDateTime)
    .GroupBy(x => x.Employee))

新:

    /// <summary>
    /// Populates HoursDuration List
    /// </summary>
    public void PopulateHoursDurationList()
    {
        HoursDurationList = new ObservableCollection<EmployeeClockSummary>();

        try
        {
            // Punches grouped by Employee
            foreach (var empInOuts in PayPeriodPunches
                .OrderBy(x => x.ClockPunchDateTime)
                .GroupBy(x => x.Employee))
            {
                int empCount = 0;
                foreach (var empPunch in empInOuts)
                {
                    if (empPunch.ClockAction == ClockAction.In)
                    {
                        // Clock In
                        HoursDurationList.Add(new EmployeeClockSummary
                        {
                            Employee = empPunch.Employee,
                            ClockInTime = empPunch.ClockPunchDateTime
                        });
                    }
                    else
                    {
                        // Clock Out
                        if (empCount == 0)
                        {
                            // This emp first punch is clock out (emp was clock in on previous pp)
                            HoursDurationList.Add(new EmployeeClockSummary
                            {
                                Employee = empPunch.Employee,
                                ClockOutTime = empPunch.ClockPunchDateTime
                            });
                        }
                        else
                        {
                            // Add clockout to previous clock in entry
                            var last = HoursDurationList[HoursDurationList.Count - 1];
                            last.ClockOutTime = empPunch.ClockPunchDateTime;
                            HoursDurationList[HoursDurationList.Count - 1] = last;
                        }                            
                    }
                    empCount++;
                }
            }
        }
        catch (Exception e)
        {
        }

        // Check for any missing ClockOuts ie still clocked in, ClockIns ie was clocked in at start
        ObservableCollection<EmployeeClockSummary> tempList = new ObservableCollection<EmployeeClockSummary>();
        foreach (var x in HoursDurationList)
        {
            var change = x;

            if (change.ClockOutTime == DateTime.MinValue
                || change.ClockOutTime == null)
            {
                // Set clock out date to now (or pp end if now passed it)
                // as they are still clocked in
                if (DateTime.Now > PayPeriodSelected.EndDateTime)
                {
                    change.ClockOutTime = PayPeriodSelected.EndDateTime;
                }
                else
                {
                    change.ClockOutTime = DateTime.Now;
                }
            }

            // Set clock in date to beginning of PP
            // as they were already clocked in when it started
            if (change.ClockInTime == DateTime.MinValue
                || change.ClockInTime == null)
            {
                change.ClockInTime = PayPeriodSelected.BeginDateTime;
            }

            tempList.Add(change);
        }

        // Group by Employee
        HoursDurationList = tempList;
        HoursDurationListView = new ListCollectionView(HoursDurationList);
        HoursDurationListView.GroupDescriptions.Add(new PropertyGroupDescription("Employee"));

    }