2

For the example below, I want to generate rows for each product as much as the dates between "Date 2" and "Date 1" and have a fourth column to include each unique day between "Date 2" and "Date 1" in these rows.

This is the input

This is the input

and this is the desired output

This is the desired output

By now, I have inserted the below formula to D2 (Dates column). This will generate the desired dates values from "Date In" to "Date Out". However, for this formula to work each product number line should be duplicated to a total count of (Date Out-Date In+1). This is where I'm stuck.

=IF(A1<>A2;B2;D1+1)

Note that there are hundreds of product code with different date values in the original data.

Thanks in advance!

3
  • Please improve your question by stating what you have tried so far and where you need help. Commented Dec 1, 2020 at 6:11
  • Use FILTER() formula if you have Excel365 with dynamic array formulas. Commented Dec 1, 2020 at 6:47
  • The part I'm stuck at added to the question. I don't know how can the FILTER() formula be utilized for my problem. Can you extend a bit? Commented Dec 1, 2020 at 6:52

3 Answers 3

3

This would be very easy to do in PowerQuery aka Get&Transform.

enter image description here

  • Select your data, under "Data" on the ribbon, choose "From Table/Range" and import to PQ (Including headers).

  • On the "Add Column" tab, click "Custom Column" and use the following formula:

    ={Number.From([Date In])..Number.From([Date Out])}
    
  • On the newly added column, click the little button on the top that shows two arrows, and choose to "Expand to New Rows".

  • Change the data type of the column to dates. Right click the title of the column, choose to change type and pick "Date".

  • If need be, change the type of "Date In" and "Date Out" back to "Date" if they changed to "Date\Time".

  • Close PQ and save your results.

enter image description here

It was as simple as that and would work very nicely if you have a full list of products with "Date In" and "Date Out".


Quick explaination of the formula:

  • To create a list in PQ we use {..}.
  • To create a list between numbers we use {1..10}.
  • We can use variables instead of numbers: {[Date In]..[Date Out]}.
  • PQ does not want dates, but need their numeric values to work, hence we can use Number.From in the final formula: {Number.From([Date In])..Number.From([Date Out])}.

You'll notice your resulting data is in a different worksheet and your source data has transformed into a proper table. A cool feature is that once you add data to this source (a new row), and hit "Refresh All" on the Data tab, it will automatically adjust your results. As mentioned in the comments below, one could also just refresh the resulting table itself:

enter image description hereenter image description here


Also, if you have Excel O365 and happen to want to create an array of dates from Date In to Date Out you could use SEQUENCE():

=SEQUENCE(C2-B2+1,,B2)
Sign up to request clarification or add additional context in comments.

4 Comments

I noticed, you also could add new rows to the original data and simply hit refresh on the pq generated table. Very neat. I really like the PQ approach to this problem. However, a side effect of this is that the original data gets converted to a table, and i can think of situations where this might be unwanted. Nothing some few lines of VBA couldn't fix i'm convinced.
Great solution. Could you share a link or two where you learned to use M-code?
@VBasic2008, I haven't "learned" M as yet. What I do is use the PQ-functions and look at the resulting code, more than often it actually reads quite logically. Whenever in doubt, the web provides thousands of sources.
Thank you for the answer! It was really basic to do. I'll look into PowerQuery capabilities in depth. It seems very functional.
2

Generating Dates Between Dates

  • The following does not account for 'surprises', e.g. a date is a string, a date is missing, start date is greater than end date, a row is empty, a worksheet is missing, there is no data...
  • Adjust the values in the constants section before using the code.

The Code

Option Explicit

Sub generateDates()
    
    ' Define constants.
    
    ' Source
    Const SourceWorksheetName As String = "Sheet1"
    Const SourceFirstCellRange As String = "A1"
    ' Target
    Const TargetWorksheetName As String = "Sheet1"
    Const TargetFirstCellRange As String = "E1"
    Const FourthTargetColumnTitle As String = "Dates"
    ' Workbook
    Dim wb As Workbook
    Set wb = ThisWorkbook
    
    ' Define Source Range.
    
    Dim cel As Range
    Set cel = wb.Worksheets(SourceWorksheetName).Range(SourceFirstCellRange)
    
    Dim rng As Range
    With cel.CurrentRegion
        Set rng = cel.Resize(.Rows.Count + .Row - cel.Row, _
            .Columns.Count + .Column - cel.Column)
    End With
    
    ' Write values from Source Range to Source Array.
    
    Dim Source As Variant
    Source = rng.Value
    
    ' Calculate the number of days for each date difference in Source Array
    ' and write the results to Days Count Array.
    
    Dim NoP As Long ' Number of Products
    NoP = UBound(Source, 1)
    
    Dim DaysCount As Variant
    ReDim DaysCount(2 To NoP)
    
    Dim i As Long ' Source Array Rows Counter
    For i = 2 To NoP
        DaysCount(i) = Source(i, 3) - Source(i, 2) + 1
    Next i
    
    ' Write values from Source Array and generates values to Target Array.
    
    Dim Target As Variant ' '1 +' is for headers.
    ReDim Target(1 To 1 + Application.Sum(DaysCount), 1 To 4)
    
    Dim j As Long ' First Three Columns Counter
    For j = 1 To 3
        Target(1, j) = Source(1, j)
    Next j
    Target(1, 4) = FourthTargetColumnTitle
    
    Dim k As Long ' Days Counter
    Dim m As Long ' Target Array Rows Counter
    m = 1 ' because of header
    For i = 2 To NoP
        For k = 1 To DaysCount(i)
            m = m + 1
            For j = 1 To 3
                Target(m, j) = Source(i, j)
            Next j
            Target(m, 4) = Source(i, 2) + k - 1
        Next k
    Next i
    
    ' Write values from Target Array to Target Range.
    
    With wb.Worksheets(TargetWorksheetName).Range(TargetFirstCellRange)
        With .Resize(, UBound(Target, 2)) ' first row
            .Resize(.Worksheet.Rows.Count - .Row + 1).ClearContents
            .Resize(UBound(Target, 1)) = Target
        End With
    End With

End Sub

1 Comment

Awesome! And very fast even for large datasets.
0

This script is far from perfect, it takes quite a long time on hundreds of records, but in the end it does what is required:

Sub extandDates()
Dim rSource As Range
Dim rRow As Range
Dim rTarget As Range
Dim dNext As Double
Application.ScreenUpdating = False
    Set rSource = ActiveSheet.UsedRange
    Set rSource = rSource.Resize(, 3)
    Set rTarget = rSource.Offset(0, rSource.Columns.Count + 2).Resize(1, 4)
    rTarget.Value = Array("Product", "Date In", "Date Out", "Dates")
    Set rTarget = rTarget.Offset(1, 0)
    Set rSource = rSource.Resize(, 1).Offset(1, 0)
    rTarget.Offset(0, 3).Resize(1, 1).EntireColumn.NumberFormat = _
             rSource.Resize(1, 1).Offset(0, 2).NumberFormat
    For Each rRow In rSource.Cells
        For dNext = rRow.Offset(0, 1).Value2 To rRow.Offset(0, 2).Value2
            rRow.Resize(1, 3).Copy Destination:=rTarget
            rTarget.Offset(0, 3).Resize(1, 1).Value2 = dNext
            Set rTarget = rTarget.Offset(1, 0)
        Next dNext
    Next rRow
Application.ScreenUpdating = True
End Sub

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.