<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Identify and isolate gaps in between date ranges in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/Identify-and-isolate-gaps-in-between-date-ranges/m-p/533518#M146287</link>
    <description>&lt;P&gt;Please post your code using a complete data step and datalines statement so we don't have to work so hard to help you out.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;As to your problem, &lt;STRONG&gt;and only considering the pattern in the data you posted&lt;/STRONG&gt;:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Use a surrogate key (record pointer) and SQL's Cartesian product to "look ahead" to the next record.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data have;
   length cat1 $1 cat2 8 start end 8;
   format start end date9.;
   informat start end mmddyy10.;
   input cat1 cat2 start end;
   datalines;
A   1   8/8/2016   10/16/2016
A   1   11/1/2016   1/10/2017
A   1   1/11/2017   4/23/2017
A   1   4/24/2017   7/19/2017
A   1   7/20/2017   9/30/2017
A   1   10/1/2017   3/31/2018
A   2   10/1/2017   4/29/2018
A   2   10/1/2017   7/1/2018
;
run;

* create surrogate key ;
data sk / view=sk;
   sk+1;
   set have;
run;

proc sql;
   * for illustration/debugging ;
   select
       a.*
      ,b.*
   from
      sk a
   join
      sk b
   on
      a.cat1=b.cat1
      and
      a.cat2=b.cat2
      and 
      a.sk=b.sk-1
   ;

   create table want as
   select
       a.cat1
      ,a.cat2
      ,a.start as old_start
      ,a.end   as old_end
      ,b.start as new_start
      ,b.end   as new_end
      ,intck('day',old_end,new_start) as gap
   from
      sk a
   join
      sk b
   on
      a.cat1=b.cat1
      and
      a.cat2=b.cat2
      and 
      a.sk=b.sk-1
   where
      intck('day',old_end,new_start) &amp;gt; 1
   ;
quit;&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;You can tidy this up a bit, dropping old_start and new_end if you wish.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;This doesn't cover say overlapping dates, where the new start date &amp;lt; old end date.&amp;nbsp; Again, see &lt;STRONG&gt;bold type&lt;/STRONG&gt; above.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Is there a typo in EffDt in your last dataline?&lt;/P&gt;</description>
    <pubDate>Thu, 07 Feb 2019 06:49:41 GMT</pubDate>
    <dc:creator>ScottBass</dc:creator>
    <dc:date>2019-02-07T06:49:41Z</dc:date>
    <item>
      <title>Identify and isolate gaps in between date ranges</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Identify-and-isolate-gaps-in-between-date-ranges/m-p/533513#M146282</link>
      <description>&lt;P&gt;I'm working on identifying events that happened in date ranges that aren't specifically covered by the data. To do this, I have a list of date ranges, some sequential, some with gaps. What I'm tyring to get is a list of date ranges that span the gaps. For example:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;TABLE&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TD&gt;Cat1&lt;/TD&gt;&lt;TD&gt;Cat2&lt;/TD&gt;&lt;TD&gt;EffDt&lt;/TD&gt;&lt;TD&gt;TermDt&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;A&lt;/TD&gt;&lt;TD&gt;1&lt;/TD&gt;&lt;TD&gt;8/8/2016&lt;/TD&gt;&lt;TD&gt;10/16/2016&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;A&lt;/TD&gt;&lt;TD&gt;1&lt;/TD&gt;&lt;TD&gt;11/1/2016&lt;/TD&gt;&lt;TD&gt;1/10/2017&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;A&lt;/TD&gt;&lt;TD&gt;1&lt;/TD&gt;&lt;TD&gt;1/11/2017&lt;/TD&gt;&lt;TD&gt;4/23/2017&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;A&lt;/TD&gt;&lt;TD&gt;1&lt;/TD&gt;&lt;TD&gt;4/24/2017&lt;/TD&gt;&lt;TD&gt;7/19/2017&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;A&lt;/TD&gt;&lt;TD&gt;1&lt;/TD&gt;&lt;TD&gt;7/20/2017&lt;/TD&gt;&lt;TD&gt;9/30/2017&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;A&lt;/TD&gt;&lt;TD&gt;1&lt;/TD&gt;&lt;TD&gt;10/1/2017&lt;/TD&gt;&lt;TD&gt;3/31/2018&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;A&lt;/TD&gt;&lt;TD&gt;2&lt;/TD&gt;&lt;TD&gt;10/1/2017&lt;/TD&gt;&lt;TD&gt;4/29/2018&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;A&lt;/TD&gt;&lt;TD&gt;2&lt;/TD&gt;&lt;TD&gt;10/1/2017&lt;/TD&gt;&lt;TD&gt;7/1/2018&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;In this case, A1 is covered from 8/8/2016 through 10/16/2016, followed by a gap from 10/17/2016 through 10/31/2016, and coevered again from 11/1/2016 through 3/31/2018. What I have been trying to get out of this is the 10/17/2016 amd 10/31/2016 values. In the event that there were multiple gaps, I'd want to identify each of them. I've been trying a few different loop permutations, but haven't been able to get anything to work quite right.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Any help would be greatly appreciated.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Thanks!&lt;/P&gt;</description>
      <pubDate>Thu, 07 Feb 2019 06:05:21 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Identify-and-isolate-gaps-in-between-date-ranges/m-p/533513#M146282</guid>
      <dc:creator>JDWall</dc:creator>
      <dc:date>2019-02-07T06:05:21Z</dc:date>
    </item>
    <item>
      <title>Re: Identify and isolate gaps in between date ranges</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Identify-and-isolate-gaps-in-between-date-ranges/m-p/533517#M146286</link>
      <description>&lt;P&gt;HI and welcome to the SAS Communities &lt;span class="lia-unicode-emoji" title=":slightly_smiling_face:"&gt;🙂&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;It is not clear to me if you want both Cat1 and Cat2 to constitute a group here. However, i think this gives you what you want. It inserts a new line with the 'date gap' whenever a date gap is detected. Let me know if it works for you.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data have;
input Cat1 $ Cat2 $ (EffDt TermDt)(:mmddyy10.);
format EffDt TermDt mmddyy10.;
datalines;
A 1 8/8/2016 10/16/2016
A 1 11/1/2016 1/10/2017
A 1 1/11/2017 4/23/2017
A 1 4/24/2017 7/19/2017
A 1 7/20/2017 9/30/2017
A 1 10/1/2017 3/31/2018
A 2 10/1/2017 4/29/2018
A 2 10/1/2017 7/1/2018
;

data want(drop= lagTermDt _:);
   set have;
   by Cat2;

   lagTermDt=lag1(TermDt);
   if first.Cat2 then lagTermDt=.;

   if intck('day', lagTermDt, EffDt)&amp;gt;1 &amp;amp; lagTermDt ne . then do;
      _EffDt=EffDt; _TermDt=TermDt;
      EffDt=lagTermDt+1;
      TermDt=_EffDt-1;
      output;

      EffDt=_EffDt; TermDt=_TermDt;
      output;return;
   end;

   output;
run;&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Thu, 07 Feb 2019 06:40:53 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Identify-and-isolate-gaps-in-between-date-ranges/m-p/533517#M146286</guid>
      <dc:creator>PeterClemmensen</dc:creator>
      <dc:date>2019-02-07T06:40:53Z</dc:date>
    </item>
    <item>
      <title>Re: Identify and isolate gaps in between date ranges</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Identify-and-isolate-gaps-in-between-date-ranges/m-p/533518#M146287</link>
      <description>&lt;P&gt;Please post your code using a complete data step and datalines statement so we don't have to work so hard to help you out.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;As to your problem, &lt;STRONG&gt;and only considering the pattern in the data you posted&lt;/STRONG&gt;:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Use a surrogate key (record pointer) and SQL's Cartesian product to "look ahead" to the next record.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data have;
   length cat1 $1 cat2 8 start end 8;
   format start end date9.;
   informat start end mmddyy10.;
   input cat1 cat2 start end;
   datalines;
A   1   8/8/2016   10/16/2016
A   1   11/1/2016   1/10/2017
A   1   1/11/2017   4/23/2017
A   1   4/24/2017   7/19/2017
A   1   7/20/2017   9/30/2017
A   1   10/1/2017   3/31/2018
A   2   10/1/2017   4/29/2018
A   2   10/1/2017   7/1/2018
;
run;

* create surrogate key ;
data sk / view=sk;
   sk+1;
   set have;
run;

proc sql;
   * for illustration/debugging ;
   select
       a.*
      ,b.*
   from
      sk a
   join
      sk b
   on
      a.cat1=b.cat1
      and
      a.cat2=b.cat2
      and 
      a.sk=b.sk-1
   ;

   create table want as
   select
       a.cat1
      ,a.cat2
      ,a.start as old_start
      ,a.end   as old_end
      ,b.start as new_start
      ,b.end   as new_end
      ,intck('day',old_end,new_start) as gap
   from
      sk a
   join
      sk b
   on
      a.cat1=b.cat1
      and
      a.cat2=b.cat2
      and 
      a.sk=b.sk-1
   where
      intck('day',old_end,new_start) &amp;gt; 1
   ;
quit;&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;You can tidy this up a bit, dropping old_start and new_end if you wish.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;This doesn't cover say overlapping dates, where the new start date &amp;lt; old end date.&amp;nbsp; Again, see &lt;STRONG&gt;bold type&lt;/STRONG&gt; above.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Is there a typo in EffDt in your last dataline?&lt;/P&gt;</description>
      <pubDate>Thu, 07 Feb 2019 06:49:41 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Identify-and-isolate-gaps-in-between-date-ranges/m-p/533518#M146287</guid>
      <dc:creator>ScottBass</dc:creator>
      <dc:date>2019-02-07T06:49:41Z</dc:date>
    </item>
    <item>
      <title>Re: Identify and isolate gaps in between date ranges</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Identify-and-isolate-gaps-in-between-date-ranges/m-p/533535#M146290</link>
      <description>&lt;P&gt;If you want to find events in another dataset that are not covered by date ranges, you can do that directly, something like&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;Proc sql;
  create table uncovered as select * from events
  where not exists(select * from date_ranges
      where cat1=events.cat1
        and cat2=events.cat2
        and events.date&amp;gt;=EffDt 
        and events.date&amp;lt;=TermDt);&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;I used the two last conditions instead of just using a BETWEEN condition because SAS SQL is peculiar in its interpretation of BETWEEN - "X between A and B" in SAS SQL can be true also in cases where A&amp;gt;B, such as your last observation, then one which&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/15043"&gt;@ScottBass&lt;/a&gt; suggested could be a typo.&lt;/P&gt;</description>
      <pubDate>Thu, 07 Feb 2019 08:43:23 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Identify-and-isolate-gaps-in-between-date-ranges/m-p/533535#M146290</guid>
      <dc:creator>s_lassen</dc:creator>
      <dc:date>2019-02-07T08:43:23Z</dc:date>
    </item>
    <item>
      <title>Re: Identify and isolate gaps in between date ranges</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Identify-and-isolate-gaps-in-between-date-ranges/m-p/533633#M146328</link>
      <description>&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data have;
input Cat1 $ Cat2 $ (EffDt TermDt)(:mmddyy10.);
format EffDt TermDt mmddyy10.;
datalines;
A 1 8/8/2016 10/16/2016
A 1 11/1/2016 1/10/2017
A 1 1/11/2017 4/23/2017
A 1 4/24/2017 7/19/2017
A 1 7/20/2017 9/30/2017
A 1 10/1/2017 3/31/2018
A 2 10/1/2017 4/29/2018
A 2 10/1/2017 7/1/2018
;

data want;
 set have;
 by cat1 cat2;
 lag=lag(TermDt);
 d=EffDt-lag;
 if d&amp;gt;1 and not first.cat2 then do;
   TermDt=EffDt-1;EffDt=lag+1;output;
 end;
 drop d lag;
run;

&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Assuming data is ordered.&lt;/P&gt;</description>
      <pubDate>Thu, 07 Feb 2019 15:49:04 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Identify-and-isolate-gaps-in-between-date-ranges/m-p/533633#M146328</guid>
      <dc:creator>Ksharp</dc:creator>
      <dc:date>2019-02-07T15:49:04Z</dc:date>
    </item>
  </channel>
</rss>

