You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Excel VBA日期分组宏优化:处理日期间隔、空行与跨月拆分

日期分组宏的功能优化需求

此为Stack Overflow线程续篇

我对最终版宏做了小幅修改,当前代码如下:

Sub GrupingByUser_pop()  
    Dim ws As Worksheet, lastR As Long, arr, arrIt, arrFin, firstDate As Date, lastDate As Date  
    Dim i As Long, j As Long, dict As Object    

    Set ws = ActiveSheet  
    lastR = ws.Range("D" & ws.Rows.Count).End(xlUp).Row 'last row on D:D    

    arr = ws.Range("A1:D" & lastR).Value 'place the range in an array for faster iteration    

    Set dict = CreateObject("scripting.Dictionary")     
    'set the necessary dictionary  
    For i = 1 To UBound(arr)  
        'if the first columns concatenation does not exist as a key, add it to dictionary:  
        If Not dict.Exists(CStr(arr(i, 1)) & "|" & arr(i, 2) & "|" & arr(i, 3)) Then  
            dict.Add CStr(arr(i, 1)) & "|" & arr(i, 2) & "|" & arr(i, 3), Array(arr(i, 4)) 'the item placed in an array  
        Else  
            arrIt = dict(CStr(arr(i, 1)) & "|" & arr(i, 2) & "|" & arr(i, 3)) 'extract the existing item in an array  
            ReDim Preserve arrIt(UBound(arrIt) + 1)                           'redim the item array preserving existing  
            arrIt(UBound(arrIt)) = arr(i, 4)                                  'place the date as the last array element  
            dict(CStr(arr(i, 1)) & "|" & arr(i, 2) & "|" & arr(i, 3)) = arrIt 'place the array back as the dict item  
        End If  
    Next i    

    'redim the final array:  
    ReDim arrFin(1 To dict.Count, 1 To 4)    

    'process the dictionary data and place them in the final array:  
    For i = 0 To dict.Count - 1  
        arrIt = Split(dict.keys()(i), "|") 'split the key by "|" separator  
        For j = 0 To UBound(arrIt): arrFin(i + 1, j + 1) = arrIt(j): Next j   'place each element in its column  

        firstDate = MakeDateFromStr(CStr(dict.Items()(i)(0))) 'extract first date  
        arrIt = dict.Items()(i)  
        lastDate = MakeDateFromStr(CStr(arrIt(UBound(arrIt)))) 'last date  
        If Month(firstDate) = Month(lastDate) Then 'if both date are inside the same month:  
           If lastDate = firstDate Then            
                'if only one date:  
                arrFin(i + 1, 4) = firstDate  
           Else                                    
                'if more dates (in the same month)  
                arrFin(i + 1, 4) = Format(Day(firstDate), "00") & " - " & Format(lastDate, "dd.mm.yyyy")  
           End If  
        Else                                        'if not in the same month:  
           arrFin(i + 1, 4) = Format(firstDate, "dd.mm.yyyy") & " - " & Format(lastDate, "dd.mm.yyyy")  
        End If  
    Next i    

    'drop the processed array result, at once:  
    Range("P1:T600").ClearContents  
    ws.Range("P1").Resize(UBound(arrFin), UBound(arrFin, 2)).Value = arrFin    

    'sort the range P1:T600 alphabetically by column P  
    With ws.Sort  
        .SortFields.Clear  
        .SortFields.Add Key:=ws.Range("P1:P600"), Order:=xlAscending  
        .SetRange ws.Range("P1:T600")  
        .Header = xlNo  
        .Apply  
    End With  
End Sub

Function MakeDateFromStr(d As String) As Date  
   MakeDateFromStr = CDate(Mid(d, 4, 2) & "/" & Left(d, 2) & "/" & Right(d, 4))  
End Function

该宏可基于多列数据为特定人员分组日期,并以「起始-结束」格式保存结果。但目前存在功能缺陷,需优化实现以下需求:

  • 若某人员的日期序列存在间隔,需拆分生成多行独立日期区间;
  • 跳过数据间的空行,解决当前宏因空行触发错误13的问题;
  • 当月度切换时,自动将日期分组拆分为独立区间。

D列日期为文本格式,宏输出格式为dd/mm/yyyy(单日期)或dd-dd/mm/yyyy(同月多日期,欧盟格式),示例如下:

数据:
![输入数据示例]

结果:
![预期结果示例]

我保留了结果列的日期对齐格式,以便直观区分单天与分组区间。


内容的提问来源于stack exchange,提问作者KMYozz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 08:57:16