VBA Excel在单元格中分隔日期范围

Posted

技术标签:

【中文标题】VBA Excel在单元格中分隔日期范围【英文标题】:VBA Excel separate range of date in cells 【发布时间】:2013-12-24 01:26:06 【问题描述】:

这让我很头疼。我正在尝试执行以下操作:

这是我拥有的数据,我有元素的名称以及开始日期和结束日期。 我想按天获取这些数据,而不是在范围内(所以我可以将它上传到我拥有的数据库中)。

我不知道我是否可以不使用 VBA 来做到这一点,但我想最快的应该是 VBA。

当前数据:

╔═══════╦════════════╦════════════╗
║ name  ║ start date ║  end date  ║
╠═══════╬════════════╬════════════╣
║ foo1  ║ 25-11-2013 ║ 28-11-2013 ║
║ foo2  ║ 25-11-2013 ║ 28-11-2013 ║
║ foo3  ║ 25-11-2013 ║ 28-11-2013 ║
║ foo4  ║ 25-11-2013 ║ 28-11-2013 ║
║ foo5  ║ 25-11-2013 ║ 28-11-2013 ║
║ foo6  ║ 28-11-2013 ║ 28-11-2013 ║
║ foo7  ║ 28-11-2013 ║ 28-11-2013 ║
║ foo8  ║ 28-11-2013 ║ 28-11-2013 ║
║ foo9  ║ 28-11-2013 ║ 28-11-2013 ║
║ foo10 ║ 28-11-2013 ║ 28-11-2013 ║
║ foo11 ║ 29-11-2013 ║ 30-11-2013 ║
║ foo12 ║ 29-11-2013 ║ 30-11-2013 ║
║ foo13 ║ 29-11-2013 ║ 30-11-2013 ║
║ foo14 ║ 29-11-2013 ║ 30-11-2013 ║
║ foo15 ║ 29-11-2013 ║ 30-11-2013 ║
╚═══════╩════════════╩════════════╝

我想按天分开名称,以获得这个:

╔═══════╦════════════╗
║ name  ║    date    ║
╠═══════╬════════════╣
║ foo1  ║ 25-11-2013 ║
║ foo2  ║ 25-11-2013 ║
║ foo3  ║ 25-11-2013 ║
║ foo4  ║ 25-11-2013 ║
║ foo5  ║ 25-11-2013 ║
║ foo1  ║ 26-11-2013 ║
║ foo2  ║ 26-11-2013 ║
║ foo3  ║ 26-11-2013 ║
║ foo4  ║ 26-11-2013 ║
║ foo5  ║ 26-11-2013 ║
║ foo1  ║ 27-11-2013 ║
║ foo2  ║ 27-11-2013 ║
║ foo3  ║ 27-11-2013 ║
║ foo4  ║ 27-11-2013 ║
║ foo5  ║ 27-11-2013 ║
║ foo6  ║ 28-11-2013 ║
║ foo7  ║ 28-11-2013 ║
║ foo8  ║ 28-11-2013 ║
║ foo9  ║ 28-11-2013 ║
║ foo10 ║ 28-11-2013 ║
║ foo11 ║ 29-11-2013 ║
║ foo12 ║ 29-11-2013 ║
║ foo13 ║ 29-11-2013 ║
║ foo14 ║ 29-11-2013 ║
║ foo15 ║ 29-11-2013 ║
║ foo11 ║ 30-11-2013 ║
║ foo12 ║ 30-11-2013 ║
║ foo13 ║ 30-11-2013 ║
║ foo14 ║ 30-11-2013 ║
║ foo15 ║ 30-11-2013 ║
╚═══════╩════════════╝

提前谢谢你。

【问题讨论】:

+1 表示格式正确的问题!您是如何为帖子创建表格格式的?很好读:) 这些类似文本的表格应该针对需要样本的 Excel 问题进行标准化......非常好。 您可以仅使用复制/粘贴来执行此操作...但是一旦将它们分开,您如何知道日期是开始日期还是结束日期?没关系吗?这似乎应该是两个字段,而不是一个。 开始日期和结束日期是否在同一列?您只是想提取开始日期吗? @Blackhawk link 【参考方案1】:

最快和最简单的方法可能是使用 VBA。以下代码循环遍历列 AC 中的值,将这些值写入列 AB 中现有数据的下方,并删除列 C 中的数据。

Sub SeperateDateRange()
    Dim Ws As Worksheet
    Dim nCol As Integer

    'Define sheet
    Set Ws = ActiveSheet

    nCol = 1 '<~~ Defines the number of columns before the date columns

    Application.ScreenUpdating = False

    'Loops throuh cells
    For i = 1 To ActiveSheet.Cells(Rows.Count, nCol + 2).End(xlUp).Row - 1 Step 1
        For j = 0 To Ws.Cells(i + 1, nCol + 2).Value - Ws.Cells(i + 1, nCol + 1).Value Step 1

            With Ws.Cells(Ws.Cells(Rows.Count, 1).End(xlUp).Row + 1, 1)
                For k = 0 To nCol - 1 Step 1
                    .Offset(0, k).Value = Ws.Cells(i + 1, k + 1).Value
                Next k
                .Offset(0, nCol).Value = DateSerial(Year(Ws.Cells(i + 1, nCol + 1).Value), Month(Ws.Cells(i + 1, nCol + 1).Value), Day(Ws.Cells(i + 1, nCol + 1).Value) + j)
            End With
        Next j
    Next i

    'Deletes last column with dates
    Ws.Cells(1, nCol + 2).EntireColumn.Delete

    Application.ScreenUpdating = True
End Sub

更新:由于 cmets 中的后续问题,现在更改了代码,以便变量 nCol 定义名称在日期列之前的列数。如果宏应该在原始问题中提供的数据上运行,那么nCol = 1。如果在有效日期之前有三列名称,则为nCol = 3

【讨论】:

您错过了日期之间的天数。如果我有一行名称为“foo”,从“25-11-2013”​​到“27-11-2013”​​,那么结果将是三行名为“foo”的行,日期为“25-11-2013”​​,“26-” 11-2013”​​和“27-11-2013”​​ 我明白了 - 我已经更新了代码。希望这能完成工作。 srrry 再次询问,但如果我在日期之前有更多列(name1、name2、name3)怎么办。我应该在代码中的哪里添加它们? 这取决于您希望他们如何在您的决赛桌中列出。你想让Name1Name2Name3都在同一列吗? 不,不同的列..与您所做的相同,但在日期之前有更多包含信息的列,输出是相同的信息列和日期列【参考方案2】:

结合@SorenHoltenHansen 的回答,这应该可以让您到达您想去的地方。此类将接受开始和结束日期范围,并将计算您可以在代码中使用的完整日期范围。

新建一个类,命名为“clsDateRange”,添加如下代码:

Option Compare Database
Option Explicit

Private m_colDates As Collection

Public Sub InitStartEnd(ByVal dtStart As Date, ByVal dtEnd As Date)
    Set m_colDates = New Collection
    Dim tempDate As Date
    For tempDate = dtStart To dtEnd Step 1
        m_colDates.Add DateValue(tempDate)
    Next
End Sub

Public Property Get Dates() As Collection
    Set Dates = m_colDates
End Property

您可以全力以赴并实现集合接口,但这应该足以满足您的需求。如果您将拥有非常大的日期范围并且您希望对此有所了解,您可以只存储开始日期和结束日期并仅在需要时生成中间日期,但我希望能够使用For...Each 无需定义 [_NewEnum] 和 Collection 的所有子属性。

以下是模块“mdlMain”中的一些测试,以便您了解如何使用它:

Public Sub Main()
    Dim oDateRange As New clsDateRange
    Dim varDate As Variant

    oDateRange.InitStartEnd "25-11-2013", "27-11-2013"
    For Each varDate In oDateRange.Dates()
        MsgBox varDate
    Next

    oDateRange.InitStartEnd "28-11-2013", "28-11-2013"
    For Each varDate In oDateRange.Dates()
        MsgBox varDate
    Next

    oDateRange.InitStartEnd "29-11-2013", "30-11-2013"
    For Each varDate In oDateRange.Dates()
        MsgBox varDate
    Next

End Sub

顺便说一句,dates are actually just 64-bit floating point numbers、Doubles。他们代表the range January 1, 100 to December 31, 9999。每一天都是 1,所以整个范围是 [-657434, 2958465]。一天中的时间表示为小数部分。午夜是 *.0,中午是 *.5,3:30 是 ~ *.645833333333333。目前(在我的时区)是 2013 年 12 月 6 日下午 1:27。根据即时窗口 ?CDbl(now()) 中的 VBA,即 41614.5608680556。

这就是为什么我可以在 for 循环中遍历日期范围的原因,每次加一以增加日期。

【讨论】:

以上是关于VBA Excel在单元格中分隔日期范围的主要内容,如果未能解决你的问题,请参考以下文章

使用 VBA 在 Excel 中处理合并和居中单元格

如何用vba实现在EXCEL固定区域坐标内点击单元格,显示日期控件

用VBA条件锁定EXCEL单元格的问题,高手进!

EXCEL VBA:根据值范围格式化现有数字单元格

Excel VBA - 如何选择范围向下到第一个空白单元格

从 vba 中的单元格地址获取 excel 合并单元格的值