Home » Create Date Range Based on Rules

Create Date Range Based on Rules

Generate the result table as shown. You need to generate dates as per the interval.

📌 Challenge Details and Links
ExcelBI Power Query Challenge Number: 46
Challenge Difficulty: ⭐️⭐️⭐️⭐️
📥Download Sample File
📥Link to the solutions on LinkedIn

Solving the challenge of Create Date Range Based on Rules with Power Query

Power Query solution 1 for Create Date Range Based on Rules, proposed by Bo Rydobon 🇹🇭:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Rec = Table.ExpandRecordColumn(
    Table.AddColumn(
      Source, 
      "R", 
      each 
        let
          Seq = {1 .. [Period]}
        in
          Record.FromList(
            List.Transform(
              Seq, 
              (n) =>
                Date.ToText(
                  Date.AddDays(
                    Date.AddMonths(
                      Date.AddDays(Date.From([Start Date]), 1), 
                      n
                        * Number.RoundDown(
                          3
                            * Number.Power(
                              2, 
                              Text.PositionOf("MQHY", Text.Start([Interval], 1)) - 1
                            )
                        )
                    ), 
                    - 1
                  ), 
                  "yyyy-MM-dd"
                )
            ), 
            List.Transform(Seq, each "Date" & Text.From(_))
          )
    ), 
    "R", 
    List.Transform({1 .. List.Max(Source[Period])}, each "Date" & Text.From(_))
  )
in
  Rec
Power Query solution 2 for Create Date Range Based on Rules, proposed by Bo Rydobon 🇹🇭:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Rec = Table.ExpandRecordColumn(
    Table.AddColumn(
      Source, 
      "R", 
      each 
        let
          Seq = {1 .. [Period]}
        in
          Record.FromList(
            List.Transform(
              Seq, 
              (n) =>
                Date.ToText(
                  Date.AddMonths(
                    Date.From([Start Date]), 
                    n
                      * Number.RoundDown(
                        3 * Number.Power(2, Text.PositionOf("MQHY", Text.Start([Interval], 1)) - 1)
                      )
                  ), 
                  "yyyy-MM-dd"
                )
            ), 
            List.Transform(Seq, each "Date" & Text.From(_))
          )
    ), 
    "R", 
    List.Transform({1 .. List.Max(Source[Period])}, each "Date" & Text.From(_))
  )
in
  Rec
Power Query solution 3 for Create Date Range Based on Rules, proposed by Aditya Kumar Darak 🇮🇳:
https://gist.github.com/Hermione-Granger-1176/d87c0fab75a6c0f634293f37af032009
                    
                  
Power Query solution 4 for Create Date Range Based on Rules, proposed by Alejandro Simón 🇵🇦 🇪🇸:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Meses = ([Year = 12, Month = 1, Half Yearly = 6, Quarter = 3]), 
  Col = List.Accumulate(
    {1 .. List.Max(Source[Period])}, 
    Source, 
    (s, c) =>
      Table.AddColumn(
        s, 
        "Date" & Text.From(c), 
        each 
          if c > [Period] then
            null
          else
            Date.ToText(
              Date.AddMonths(
                Date.From([Start Date]), 
                Record.ToList(Meses){List.PositionOf(Record.FieldNames(Meses), [Interval])} * c
              ), 
              "yyyy-MM-dd"
            )
      )
  )
in
  Col
Power Query solution 5 for Create Date Range Based on Rules, proposed by Luan Rodrigues:
let
  Fonte = Tabela1, 
  Col = Table.DuplicateColumn(Fonte, "Interval", "Interval_c"), 
  Sub = {{"Year", 12}, {"Month", 1}, {"Half Yearly", 6}, {"Quarter", 3}}, 
  sub1 = Table.TransformColumns(
    Col, 
    {
      {
        "Interval_c", 
        each Text.Combine(
          List.Transform(List.ReplaceMatchingItems(Lines.FromText(_), Sub), Text.From), 
          " "
        ), 
        type text
      }
    }
  ), 
  seq = Table.AddColumn(sub1, "Personalizar", each {0 .. [Period]}), 
  exp = Table.ExpandListColumn(seq, "Personalizar"), 
  rec = Table.AddColumn(
    exp, 
    "Personalizar1", 
    each [
      a = Date.From([Start Date]), 
      b = Date.EndOfMonth(Date.From([Start Date])), 
      c = Date.AddMonths(a, + Number.From([Interval_c]) * [Personalizar]), 
      d = Date.EndOfMonth(Date.AddMonths(a, + Number.From([Interval_c]) * [Personalizar])), 
      e = if a = b then d else c
    ][e]
  ), 
  Tipo = Table.TransformColumnTypes(rec, {{"Personalizar1", type date}}, "en-US"), 
  gp = Table.Group(
    Tipo, 
    {"Period", "Interval"}, 
    {{"Date", each Text.Combine(List.Transform([Personalizar1], Text.From), "|")}}
  ), 
  cnt = List.Max(
    Table.AddColumn(
      gp, 
      "Personalizar", 
      each List.Count(Text.ToList(Text.Select([Date], {"|"}))) + 1
    )[Personalizar]
  ), 
  Result = Table.SplitColumn(gp, "Date", Splitter.SplitTextByDelimiter("|", QuoteStyle.Csv), cnt)
in
  Result
Power Query solution 6 for Create Date Range Based on Rules, proposed by Bhavya Gupta:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Replacements = List.Buffer({{"Year", 12}, {"Month", 1}, {"Half Yearly", 6}, {"Quarter", 3}}), 
  AddedCustom = Table.AddColumn(
    Source, 
    "Dates", 
    each List.Transform(
      List.Skip(
        List.Numbers(0, [Period] + 1, List.ReplaceMatchingItems({[Interval]}, Replacements){0})
      ), 
      (m) => Date.ToText(Date.AddMonths(Date.From([Start Date]), m), "yyyy-MM-dd")
    )
  ), 
  Custom = List.Transform(
    {1 .. List.Max(List.Transform(AddedCustom[Dates], List.Count))}, 
    each "Date" & Text.From(_)
  ), 
  RecordfromList = Table.ReplaceValue(
    AddedCustom, 
    null, 
    null, 
    (a, b, c) => Record.FromList(a, List.FirstN(Custom, List.Count(a))), 
    {"Dates"}
  ), 
  ExpectedOutput = Table.ExpandRecordColumn(RecordfromList, "Dates", Custom, Custom)
in
  ExpectedOutput
Power Query solution 7 for Create Date Range Based on Rules, proposed by 🇮🇷 Navid Esmaeilzadeh اسماعیل زاده:
Part2:
#"Removed Columns" = Table.RemoveColumns(#"Merged Columns",{"In-Month"}),
 Pivot = Table.Pivot(#"Removed Columns", List.Distinct(#"Removed Columns"[List]), "List", "Date"),
 Split = Table.SplitColumn(Pivot, "Merged", Splitter.SplitTextByDelimiter("|", QuoteStyle.Csv), {"Merged.1", "Merged.2", "Merged.3"}),
 Ch2 = Table.TransformColumnTypes(Split,{{"Merged.1", Int64.Type}, {"Merged.2", type text}, {"Merged.3", type date}}),
 Rename = Table.RenameColumns(Ch2,{{"Merged.1", "Period"}, {"Merged.2", "Interval"}, {"Merged.3", "Start Date"}}),
 Ch3 = Table.TransformColumnTypes(Rename,{{"Period", Int64.Type}, {"Interval", type text}, {"Start Date", type date}, {"Date 1", type date}, {"Date 2", type date}, {"Date 3", type date}, {"Date 4", type date}, {"Date 5", type date}, {"Date 6", type date}, {"Date 7", type date}, {"Date 8", type date}, {"Date 9", type date}})
in
 Ch3
                    
                  
Power Query solution 8 for Create Date Range Based on Rules, proposed by 🇮🇷 Navid Esmaeilzadeh اسماعیل زاده:
let
 Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
 Ch = Table.TransformColumnTypes(Source,{{"Period", Int64.Type}, {"Interval", type text}, {"Start Date", type date}}),
 ACC = Table.AddColumn(Ch, "In-Month", each if [Interval] = "Year" then 12 else if [Interval] = "Half Yearly" then 6 else if [Interval] = "Quarter" then 3 else 1),
 AC = Table.AddColumn(ACC, "List", each {0.. [Period]}),
 ExL = Table.ExpandListColumn(AC, "List"),
 Ch1 = Table.TransformColumnTypes(ExL,{{"Period", Int64.Type}, {"Interval", type text}, {"Start Date", type date}, {"In-Month", Int64.Type}, {"List", Int64.Type}}),
 Ac1 = Table.AddColumn(Ch1, "Date", each Date.AddMonths([Start Date],[#"In-Month"]*[List])),
 Filter = Table.SelectRows(Ac1, each ([List] <> 0)),
 #"Added Prefix" = Table.TransformColumns(Filter, {{"List", each "Date " & Text.From(_, "en-US"), type text}}),
 #"Merged Columns" = Table.CombineColumns(Table.TransformColumnTypes(#"Added Prefix", {{"Period", type text}, {"Start Date", type text}}, "en-US"),{"Period", "Interval", "Start Date"},Combiner.CombineTextByDelimiter("|", QuoteStyle.None),"Merged"),
 
                    
                  
          
Power Query solution 9 for Create Date Range Based on Rules, proposed by Matthias Friedmann:
let
  Source = Excel.CurrentWorkbook(){[Name = "AddPeriod"]}[Content], 
  Type = Table.TransformColumnTypes(Source, {{"Start Date", type date}}), 
  Added = Table.AddColumn(
    Type, 
    "Dates", 
    each [
      period = [Period], 
      interval = 
        if [Interval] = "Year" then
          12
        else if [Interval] = "Half Yearly" then
          6
        else if [Interval] = "Quarter" then
          3
        else
          1, 
      start = [Start Date], 
      list = List.Generate(
        () => [date = Date.AddMonths(start, interval), i = 1], 
        each [i] <= period, 
        each [date = Date.AddMonths(start, interval * ([i] + 1)), i = [i] + 1], 
        each [date]
      ), 
      EoM = 
        if start = Date.EndOfMonth(start) then
          List.Transform(list, each Date.EndOfMonth(_))
        else
          list
    ][EoM]
  ), 
  Extracted = Table.TransformColumns(
    Added, 
    {"Dates", each Text.Combine(List.Transform(_, Text.From), ","), type text}
  ), 
  Split = Table.SplitColumn(
    Extracted, 
    "Dates", 
    Splitter.SplitTextByDelimiter(",", QuoteStyle.Csv), 
    List.Max(Extracted[Period])
  )
in
  Split
Power Query solution 11 for Create Date Range Based on Rules, proposed by Thomas DUCROQUETZ:
let
  Source = YourRawData, 
  ModifType = Table.TransformColumnTypes(
    Source, 
    {{"Period", Int64.Type}, {"Interval", type text}, {"Start Date", type date}}
  ), 
  MaxInterval = List.Max(ModifType[Period]), 
  AddDates = List.Accumulate(
    {1 .. MaxInterval}, 
    ModifType, 
    (Table, currentNumber) =>
      Table.AddColumn(
        Table, 
        "Date" & Number.ToText(currentNumber), 
        each 
          let
            dateFunc = 
              if [Interval] = "Year" then
                (d) => Date.AddYears(d, currentNumber)
              else if [Interval] = "Month" then
                (d) => Date.AddMonths(d, currentNumber)
              else if [Interval] = "Half Yearly" then
                (d) => Date.AddMonths(d, 6 * currentNumber)
              else if [Interval] = "Quarter" then
                (d) => Date.AddQuarters(d, currentNumber)
              else
                (d) => d
          in
            if currentNumber <= [Period] then dateFunc([Start Date]) else null, 
        type date
      )
  )
in
  AddDates
Power Query solution 12 for Create Date Range Based on Rules, proposed by Fábio Gatti:
let
 Source = Table,

 Col_Periods = Table.AddColumn(Source , "Periods", each
 let
 vInterval = [Interval],
 vDate = Date.From([Start Date])
 in
 List.Transform(
 {1..[Period]},
 each
 let 
 vDateValue =
 if vInterval = "Year"
 then Date.AddYears(vDate, _)
 else if vInterval = "Month"
 then Date.AddMonths(vDate, _)
 else if vInterval = "Half Yearly"
 then Date.EndOfMonth(Date.AddMonths(vDate, _ * 6))
 else if vInterval = "Quarter"
 then Date.AddQuarters(vDate, _)
 else
 hashtag#date(1900,1,1) 
 in
 [
 Date = "Date " & Text.From(_),
 DateValue = Date.ToText(vDateValue, "yyyy-MM-dd")
 ]
 )
 ),

 Expand_Periods = Table.ExpandListColumn(Col_Periods, "Periods"),
 Expand_Periods2 = Table.ExpandRecordColumn(Expand_Periods, "Periods", {"Date", "DateValue"}, {"Date", "DateValue"}),
 Pivot_Periods = Table.Pivot(Expand_Periods2, List.Distinct(Expand_Periods2[Date]), "Date", "DateValue")
in
 Pivot_Periods


                    
                  
          

Solving the challenge of Create Date Range Based on Rules with Excel

Excel solution 1 for Create Date Range Based on Rules, proposed by Bo Rydobon 🇹🇭:
=LET(z,A2:C7,p,TAKE(z,,1),s,SEQUENCE(,MAX(p)),
VSTACK(HSTACK(A1:C1,"Date"&s),HSTACK(z,IF(p
Excel solution 2 for Create Date Range Based on Rules, proposed by Rick Rothstein:
=LET(
    s,
    SEQUENCE(
        ,
        A2
    ),
    l,
    LEFT(
        B2
    ),
    e,
    EDATE(
        C2,
        CHOOSE(
            FIND(
                l,
                "YMHQ"
            ),
            12,
            1,
            6,
            3
        )*s
    ),
    IF(
        EOMONTH(
            C2,
            0
        )=C2,
        EOMONTH(
            e,
            0
        ),
        e
    )
)
Excel solution 3 for Create Date Range Based on Rules, proposed by Zoran Milokanović:
= 'NO' THEN DATEADD(YEAR, 1, C.START_DATE) ELSE EOMONTH(DATEADD(YEAR, 1, C.START_DATE)) END)
 WHEN 'Half Yearly' THEN (CASE WHEN C.EOM_FLAG = 'NO' THEN DATEADD(QUARTER, 2, C.START_DATE) ELSE EOMONTH(DATEADD(QUARTER, 2, C.START_DATE)) END)
 WHEN 'Quarter' THEN (CASE WHEN C.EOM_FLAG = 'NO' THEN DATEADD(QUARTER, 1, C.START_DATE) ELSE EOMONTH(DATEADD(QUARTER, 1, C.START_DATE)) END)
 WHEN 'Month' THEN (CASE WHEN C.EOM_FLAG = 'NO' THEN DATEADD(MONTH, 1, C.START_DATE) ELSE EOMONTH(DATEADD(MONTH, 1, C.START_DATE)) END)
 END AS DATE) AS START_DATE
 ,C.DATE_SEQ + 1 AS DATE_SEQ
 FROM CALC C
 WHERE
 C.DATE_SEQ <= C.PERIOD
)
SELECT
 P.PERIOD
,P.INTERVAL
,P.[1] AS START_DATE, P.[2] AS DATE1, P.[3] AS DATE2, P.[4] AS DATE3, P.[5] AS DATE4, P.[6] AS DATE5, P.[7] AS DATE6, P.[8] AS DATE7, P.[9] AS DATE8, P.[10] AS DATE9
FROM CALC C
PIVOT
(
 MAX(C.START_DATE)
 FOR C.DATE_SEQ IN ([1], [2], [3], [4], [5], [6], [7], [8], [9], [10])
)
Excel solution 4 for Create Date Range Based on Rules, proposed by محمد حلمي:
=HSTACK(A2:C7,
IFNA(DROP(
REDUCE(0,SEQUENCE(ROWS(B2:B7)),
LAMBDA(a,d,
VSTACK(a,
LET(s,SEQUENCE(,INDEX(A2:A7,d)),
b,INDEX(B2:B7,d),
EDATE(INDEX(C2:C7,d),
IFS(
b="Year",s*12,
b="Half Yearly",s*6,
b="Month",s*1,
b="Quarter",s*3)))))),1),""))
Excel solution 5 for Create Date Range Based on Rules, proposed by محمد حلمي:
=LET(
s,SEQUENCE(,A2),
EDATE(C2,
IFS(
B2="Year",s*12,
B2="Half Yearly",s*6,
B2="Month",s*1,
B2="Quarter",s*3)))
Excel solution 6 for Create Date Range Based on Rules, proposed by 🇰🇷 Taeyong Shin:
=LET(
 intv, SWITCH(B2:B7, "Year", 12, "Month", 1, "Half Yearly", 6, "Quarter", 3),
 P, A1:A7,
 Dt, C2:C7,
 nums, MAKEARRAY(ROWS(P), MAX(P), LAMBDA(r,c,
 IF(r = 1, "Date" & c, IF(c > @INDEX(P, r), "", c))
 )),
 HSTACK(A1:C7, VSTACK(TAKE(nums, 1), IFERROR(EDATE(+Dt, intv * DROP(nums, 1)), "")))
)
=LET(
 Intv, VLOOKUP(B2:B7, {"Year",12;"Month",1;"Half Yearly",6;"Quarter",3}, 2, 0),
 n, IFNA(SEQUENCE(, MAX(A2:A7)), A2:A7),
 HSTACK(
 A1:C7,
 VSTACK(
 "Date" & TAKE(n, 1),
 REPT(TEXT(EDATE(+C2:C7, Intv * n), "yyyy-mm-dd"), n <= A2:A7)
 )
 )
)
Excel solution 7 for Create Date Range Based on Rules, proposed by Aditya Kumar Darak 🇮🇳:
=LET(
 _d, A1:C7,
 _h, TAKE(_d, 1),
 _b, DROP(_d, 1),
 _ct, "MQHY",
 _pd, TAKE(_b, , 1),
 _int, INDEX(_b, 0, 2),
 _dt, --TAKE(_b, , -1),&
 _du, CHOOSE(FIND(LEFT(_int), _ct), 1, 3, 6, 12),
 _mx, SEQUENCE(1, MAX(_pd)),
 _e, LAMBDA(a, b,
 HSTACK(
 a,
 IFS(
 b > _pd,
 "",
 _dt = EOMONTH(_dt, 0),
 EOMONTH(_dt, b * _du),
 1,
 EDATE(_dt, b * _du)
 )
 )
 ),
 _c, REDUCE(_dt, _mx, _e),
 _fh, HSTACK(_h, "Date" & _mx),
 _fb, HSTACK(TAKE(_b, , 2), TEXT(_c, "yyyy-mm-dd")),
 _r, VSTACK(_fh, _fb),
 _r
)
Excel solution 8 for Create Date Range Based on Rules, proposed by Quadri Olayinka Atharu:
=EDATE(Startdate,SEQUENCE(,Period,Interval,Interval))

Solving the challenge of Create Date Range Based on Rules with SQL

SQL solution 1 for Create Date Range Based on Rules, proposed by Zoran Milokanović:
1/2
WITH /* Microsoft SQL Server 2019 */
DATA_PREP
AS
(
 SELECT
 ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS ORDERING
 ,D.PERIOD
 ,D.INTERVAL
 ,CAST(CONVERT(VARCHAR, D.START_DATE, 120) AS DATE) AS START_DATE
 FROM DATA D
),
                    
                  

&&

Leave a Reply