• 20190319xlVBA_根据考勤数据统计缺勤缺考数据


    Sub SubtotalPickFile()
        Dim StartTime As Variant
        Dim UsedTime As Variant
        StartTime = VBA.Timer
        Dim firstday As Date, lastday As Date
        Dim Wb As Workbook
        Dim Sht As Worksheet
        Dim oSht As Worksheet
        Dim Dic As Object
        Dim d As Object
        Set d = CreateObject("Scripting.Dictionary")
        Set ud = CreateObject("Scripting.Dictionary")
        Set Dic = CreateObject("Scripting.Dictionary")
        Dim onDay, onTime, offTime
        Const ON_TIME = "8:30:00"
        Const OFF_TIME = "17:00:00"
        Const MID_TIME = "12:00:00"
        Dim onForget, offForget, onLate, offEarly, forgetTime, lateTime, earlyTime, duration
        Dim lateday, earlyday, forgetday
        Set Wb = ThisWorkbook
        
        '选取考勤数据文件
        FilePath = FilePicker()
        If FilePath = "" Then Exit Sub
        Set OpenWb = Application.Workbooks.Open(FilePath)
        Set Sht = OpenWb.Worksheets(1)
        With Sht
            endrow = .Cells(.Cells.Rows.Count, 1).End(xlUp).Row
            Set Rng = .Range("A3:F" & endrow)
            arr = Rng.Value
        End With
        OpenWb.Close False
        
        '设置考勤起止日期
        startday = Application.InputBox("请输入起始日期,格式为 2019/01/01 : ", "InputBox", , , , , , 2)
        If startday = False Then
            MsgBox "没有输入日期!"
            Exit Sub
        End If
       endday = Application.InputBox("请输入结束日期,格式为 2019/01/31 : ", "InputBox", , , , , , 2)
        If endday = False Then
            MsgBox "没有输入日期!"
            Exit Sub
        End If
        
        '计算工作日天数
        On Error Resume Next
        firstday = CDate(startday)
        lastday = CDate(endday)
        'wkdays = WorkdaysBetween(firstday, lastday)
        
        counter = 0
        today = firstday
        Do
                    Key = Format(today, "yyyy/mm/dd")
            If Weekday(today, vbMonday) <= 5 Then
                counter = counter + 1
    
                d(Key) = ""
                ''debug.Print today; " 是工作日  "; counter
            Else
                ud(Key) = ""
                ''Debug.Print today; " 是工作日  "; counter
            End If
            
            today = DateAdd("d", 1, today)
            If today = DateAdd("d", 1, lastday) Then Exit Do
        Loop
        wkdays = counter
        
        
        
        
        If Err.Number <> 0 Then
            Exit Sub
            MsgBox "输入的日期范围可能有误!", vbInformation, "Information"
        End If
        
        Set oSht = Wb.Worksheets("result")
        For i = LBound(arr) To UBound(arr)
            Key = CStr(arr(i, 2))
            td = CDate(arr(i, 4))
            If DateDiff("d", firstday, td) >= 0 And DateDiff("d", td, lastday) >= 0 Then
                ''debug.Print td; "   符合要求"
                '截取上下班时间
                onTime = CDate(Split(arr(i, 5), " ")(1))
                offTime = CDate(Split(arr(i, 6), " ")(1))
                onForget = False
                offForget = False
                
                '计算工作时长
                duration = DateDiff("n", onTime, offTime)
                If Not Dic.Exists(Key) Then
                    lateTime = 0
                    earlyTime = 0
                    forgetTime = 0
                    forgetday = ""
                    lateday = ""
                    earlyday = ""
                    onDay = 1
                    '迟到判断
                    onLate = (DateDiff("s", CDate(ON_TIME), onTime) > 0)
                    onForget = (DateDiff("s", CDate(MID_TIME), onTime) > 0)
                    If onForget Then
                        forgetTime = forgetTime + 1
                        forgetday = arr(i, 4) & "上午"
                    Else
                        If onLate Then
                            If duration < 510 Then
                                lateTime = lateTime + 1
                                If lateday = "" Then
                                    lateday = arr(i, 4) & "上午"
                                Else
                                    lateday = lateday & vbCrLf & arr(i, 4) & "上午"
                                End If
                            End If
                        End If
                    End If
                    '早退判断
                    offEarly = (DateDiff("s", offTime, CDate(OFF_TIME)) > 0)
                    offForget = (DateDiff("s", CDate(MID_TIME), offTime) < 0)
                    If offForget Then
                        forgetTime = forgetTime + 1
                        If forgetday <> "" Then
                            forgetday = forgetday & vbCrLf & arr(i, 4) & "下午"
                        Else
                            forgetday = arr(i, 4) & "下午"
                        End If
                    Else
                        If offEarly Then
                            If duration < 510 Then
                                earlyTime = earlyTime + 1
                                If earlyday = "" Then
                                    earlyday = arr(i, 4) & "下午"
                                Else
                                    earlyday = earlyday & vbCrLf & arr(i, 4) & "下午"
                                End If
                            End If
                        End If
                    End If
                    ar = Array(arr(i, 1), arr(i, 2), arr(i, 3), wkdays, onDay, 0, Format(arr(i, 4), "yyyy/mm/dd"), lateTime, lateday, earlyTime, earlyday, forgetTime, forgetday)
                    Dic(Key) = ar
                Else
                    ar = Dic(Key)
                    ar(4) = ar(4) + 1
                    ar(6) = ar(6) & ";" & Format(arr(i, 4), "yyyy/mm/dd")
                   'If Key = "2018000766" Then Debug.Print td; "    ----------"; ar(6)
                    '迟到判断
                    onLate = (DateDiff("s", CDate(ON_TIME), onTime) > 0)
                    onForget = (DateDiff("s", CDate(MID_TIME), onTime) > 0)
                    If onForget Then
                        ar(11) = ar(11) + 1
                        If ar(12) <> "" Then
                            ar(12) = ar(12) & vbCrLf & arr(i, 4) & "上午"
                        Else
                            ar(12) = arr(i, 4) & "上午"
                        End If
                    Else
                        If onLate Then
                            If duration < 510 Then
                                ar(7) = ar(7) + 1
                                If ar(8) = "" Then
                                    ar(8) = arr(i, 4) & "上午"
                                Else
                                    ar(8) = ar(8) & vbCrLf & arr(i, 4) & "上午"
                                End If
                            End If
                        End If
                    End If
                    '早退判断
                    offEarly = (DateDiff("s", offTime, CDate(OFF_TIME)) > 0)
                    offForget = (DateDiff("s", CDate(MID_TIME), offTime) < 0)
                    If offForget Then
                        ar(11) = ar(11) + 1
                        If ar(12) <> "" Then
                            ar(12) = ar(12) & vbCrLf & arr(i, 4) & "下午"
                        Else
                            ar(12) = arr(i, 4) & "下午"
                        End If
                    Else
                        If offEarly Then
                            If duration < 510 Then
                                ar(9) = ar(9) + 1
                                If ar(10) = "" Then
                                    ar(10) = arr(i, 4) & "下午"
                                Else
                                    ar(10) = ar(10) & vbCrLf & arr(i, 4) & "下午"
                                End If
                            End If
                        End If
                    End If
                    Dic(Key) = ar
                End If
            End If
        Next i
        
        '计算缺考天数和缺考日期
        'On Error Resume Next
        For Each K In Dic.keys
            ar = Dic(K)
            ar(4) = UBound(ar(6)) + 1
            ar(5) = ar(3) - ar(4)
              'If K = "2018000766" Then Debug.Print "缺考天数 : "; ar(5)
              'If K = "2018000766" Then Debug.Print ar(2); " 打卡日期: "; ar(6)
             s = ""
             For Each wd In d.keys
                 'If K = "2018000766" Then Debug.Print "工作日》》"; wd
                 'If K = "2018000766" Then Debug.Print "判断日期在不在工作日内:"; wd; "  "; InStr(ar(6), wd)
                If InStr(ar(6), wd) <= 0 Then
                    If s = "" Then
                        s = wd & "缺考"
                    Else
                        s = s & vbCrLf & wd & "缺考"
                    End If
                End If
             Next wd
             
             w = ""
             For Each u In ud.keys
                If K = "2018000766" Then Debug.Print "非工作日》》"; u
                If K = "2018000766" Then Debug.Print "判断日期在不在工作日内:"; u; "  "; InStr(ar(6), u)
                If InStr(ar(6), u) > 0 Then
                    If w = "" Then
                        w = u & "加班"
                    Else
                        w = w & vbCrLf & u & "加班"
                    End If
                End If
             Next u
             
     
               'If K = "2018000766" Then Debug.Print ar(2); " 缺考日期: "; s
               'If K = "2018000766" Then Debug.Print ar(2); " 加班日期: "; w
            ar(6) = s & vbCrLf & w
            Dic(K) = ar
               
       
        Next K
        
        
        With oSht
            .UsedRange.Offset(2).Clear
            Set Rng = .Range("A3")
            Set Rng = Rng.Resize(Dic.Count, 13)
            Rng.Value = Application.Rept(Dic.Items, 1)
            Sort_2003 Rng, False
            SetCenters .UsedRange
            SetBorders .UsedRange
            .Activate
            Rows("3:3").Select
            ActiveWindow.FreezePanes = True
        End With
        
        Call StepForward
        
        UsedTime = VBA.Timer - StartTime
        ''debug.Print "UsedTime :" & Format(UsedTime, "#0.0000 Seconds")
        MsgBox "UsedTime :" & Format(UsedTime, "#0.0000 Seconds")
        Set Dic = Nothing
        Set Wb = Nothing
        Set Sht = Nothing
        Set oSht = Nothing
        Set OpenWb = Nothing
    End Sub
    Private Sub SetBorders(ByVal Rng As Range)
        With Rng.Borders
            .LineStyle = xlContinuous
            .ColorIndex = xlAutomatic
            .TintAndShade = 0
            .Weight = xlThin
        End With
    End Sub
    Private Sub SetCenters(ByVal Rng As Range)
        With Rng
            .HorizontalAlignment = xlCenter
            .VerticalAlignment = xlCenter
            .WrapText = True
            '.Columns.AutoFit
        End With
    End Sub
    'FilePath=FilePicker(InitialPath)
    'If FilePath = "" Then Exit Sub
    Function FilePicker(Optional InitialPath As String = "")
        Dim FilePath As String
        If InitialPath = "" Then
            InitialPath = Application.ActiveWorkbook.Path
        End If
        With Application.FileDialog(msoFileDialogFilePicker)
            .AllowMultiSelect = False
            .InitialFileName = InitialPath
            .Title = "请选择单个Excel工作簿"
            .Filters.Clear
            .Filters.Add "Excel工作簿", "*.xls*"
            If .Show = -1 Then
                FilePath = .SelectedItems(1)
            Else
                MsgBox "您没有选中任何文件,本次汇总中断!"
            End If
        End With
        FilePicker = FilePath
    End Function
    Function WorkdaysInMonth(ByVal month As Date)
        Dim counter
        counter = 0
        firstday = CDate(Format(month, "yyyy/mm") & "/01")
        lastday = DateAdd("d", -1, CDate(Format(DateAdd("m", 1, month), "yyyy/mm") & "/01"))
        today = firstday
        Do
            If Weekday(today, vbFriday) <= 5 Then counter = counter + 1
            today = DateAdd("d", 1, today)
            If today = lastday Then Exit Do
        Loop
        WorkdaysInMonth = counter
    End Function
    Function WorkdaysBetween(ByVal firstday As Date, ByVal lastday As Date)
        Dim counter
        today = firstday
        Do
            If Weekday(today, vbFriday) <= 5 Then counter = counter + 1
            today = DateAdd("d", 1, today)
            If today = lastday Then Exit Do
        Loop
        WorkdaysBetween = counter
    End Function
    Function IsWorkday(ByVal OneDay As Date) As Boolean
           IsWorkday = (Weekday(OneDay, vbMonday) <= 5)
       '  ''debug.Print OneDay; " 是工作日  "; IsWorkday
    End Function
    Private Sub Sort_2003(ByVal Rng As Range, Optional WithHeader As Boolean = True)
        With Rng 'xlAscending
                .Sort _
                Key1:=Rng.Cells(1, 1), Order1:=xlAscending, _
                Header:=IIf(WithHeader, xlYes, xlNo), _
                MatchCase:=False, _
                Orientation:=xlTopToBottom, _
                SortMethod:=xlPinYin
        End With
    End Sub
    

      

    Public Sub StepForward()
        Dim Dic As Object
        Dim Wb As Workbook
        Dim Sht As Worksheet
        Dim oSht As Worksheet
        
        Set Wb = Application.ThisWorkbook
        Set Dic = CreateObject("Scripting.Dictionary")
        Set Sht = Wb.Worksheets("result")
        Set oSht = Wb.Worksheets("analyze")
        With Sht
            endrow = .Cells(.Cells.Rows.Count, 1).End(xlUp).Row
            Set Rng = .Range("A3:M" & endrow)
            arr = Rng.Value
            
            For i = LBound(arr) To UBound(arr)
                Key = CStr(arr(i, 2))
                company = arr(i, 1)
                staff = arr(i, 3)
                
                IsSave = False
                
                If arr(i, 6) >= 1 Then
                    debt = arr(i, 6)
                    IsSave = True
                Else
                    debt = ""
                End If
                
                If arr(i, 8) >= 3 Then
                    late = arr(i, 8)
                     IsSave = True
                Else
                    late = ""
                End If
                
                If arr(i, 10) >= 3 Then
                    early = arr(i, 10)
                     IsSave = True
                Else
                    early = ""
                End If
                
                If arr(i, 12) >= 3 Then
                    forget = arr(i, 12)
                     IsSave = True
                Else
                    forget = ""
                End If
                
               If IsSave Then Dic(Key) = Array(company, Key, staff, debt, late, early, forget)
                
            Next i
            
        End With
        
        
        With oSht
            .UsedRange.Offset(2).Clear
            Set Rng = .Range("A3")
            Set Rng = Rng.Resize(Dic.Count, 7)
            Rng.Value = Application.Rept(Dic.Items, 1)
            SetCenters .UsedRange
            SetBorders .UsedRange
            Sort_2003 Rng, False
            .Activate
            Rows("3:3").Select
            ActiveWindow.FreezePanes = True
        End With
        
        UsedTime = VBA.Timer - StartTime
        
        
        
    End Sub
    Private Sub SetBorders(ByVal Rng As Range)
        With Rng.Borders
            .LineStyle = xlContinuous
            .ColorIndex = xlAutomatic
            .TintAndShade = 0
            .Weight = xlThin
        End With
    End Sub
    Private Sub SetCenters(ByVal Rng As Range)
        With Rng
            .HorizontalAlignment = xlCenter
            .VerticalAlignment = xlCenter
            .WrapText = True
            '.Columns.AutoFit
        End With
    End Sub
    Private Sub Sort_2003(ByVal Rng As Range, Optional WithHeader As Boolean = True)
        With Rng 'xlAscending
                .Sort _
                Key1:=Rng.Cells(1, 1), Order1:=xlAscending, _
                Header:=IIf(WithHeader, xlYes, xlNo), _
                MatchCase:=False, _
                Orientation:=xlTopToBottom, _
                SortMethod:=xlPinYin
        End With
    End Sub
    

      

  • 相关阅读:
    https单向证书
    单例模式再学习
    sql经常出现死锁解决办法
    sqlserver结束和监视耗时的sql
    如何保持进步
    es6-学习
    javascript修改div大小遮挡页面渲染问题
    报表功能设计思考-初步尝试-第一次
    导出统计数据-经验积累-深入1
    Java中数据类型转换&基本类型变量和对象型变量
  • 原文地址:https://www.cnblogs.com/nextseven/p/10562623.html
Copyright © 2020-2023  润新知