diff --git a/src/parser/calendar/data/PhutilCalendarRecurrenceRule.php b/src/parser/calendar/data/PhutilCalendarRecurrenceRule.php
--- a/src/parser/calendar/data/PhutilCalendarRecurrenceRule.php
+++ b/src/parser/calendar/data/PhutilCalendarRecurrenceRule.php
@@ -42,8 +42,6 @@
   private $stateMonth;
   private $stateYear;
 
-  private $initialMonth;
-  private $initialYear;
   private $baseYear;
   private $isAllDay;
   private $activeSet = array();
@@ -324,8 +322,6 @@
     // TODO: Figure this out.
     $this->cursorWeek = null;
     $this->cursorDay = $date->getDay();
-    $this->cursorDayMonth = $date->getMonth();
-    $this->cursorDayYear = $date->getYear();
     $this->cursorMonth = $date->getMonth();
     $this->cursorYear = $date->getYear();
 
@@ -356,9 +352,19 @@
           break;
         case self::FREQUENCY_MONTHLY:
           $this->cursorMonth -= $interval;
+
           while ($this->cursorMonth < 1) {
-            $this->cursorYear--;
-            $this->cursorMonth += 12;
+            $this->rewindMonth();
+          }
+          break;
+        case self::FREQUENCY_DAILY:
+          $this->cursorDay -= $interval;
+
+          $week_start = $this->getWeekStart();
+          while ($this->cursorDay < 1) {
+            $year_map = $this->getYearMap($this->cursorYear, $week_start);
+            $this->cursorDay += $year_map['monthDays'][$this->cursorMonth];
+            $this->rewindMonth();
           }
           break;
         default:
@@ -373,9 +379,8 @@
       $this->minimumEpoch = null;
     }
 
-
-    $this->initialMonth = $this->cursorMonth;
-    $this->initialYear = $this->cursorYear;
+    $this->cursorDayMonth = $this->cursorMonth;
+    $this->cursorDayYear = $this->cursorYear;
 
     $by_hour = $this->getByHour();
     $by_minute = $this->getByMinute();
@@ -1230,8 +1235,16 @@
     if ($scale < self::SCALE_YEARLY) {
       $parts[] = $this->stateMonth;
     }
+    if ($scale < self::SCALE_MONTHLY) {
+      $parts[] = $this->stateDay;
+    }
 
     return implode('/', $parts);
   }
 
+  private function rewindMonth() {
+    $this->cursorYear--;
+    $this->cursorMonth += 12;
+  }
+
 }
diff --git a/src/parser/calendar/data/__tests__/PhutilCalendarRecurrenceRuleTestCase.php b/src/parser/calendar/data/__tests__/PhutilCalendarRecurrenceRuleTestCase.php
--- a/src/parser/calendar/data/__tests__/PhutilCalendarRecurrenceRuleTestCase.php
+++ b/src/parser/calendar/data/__tests__/PhutilCalendarRecurrenceRuleTestCase.php
@@ -723,7 +723,7 @@
     );
 
     // This is testing that INTERVAL is respected in the presence of a BYMONTH
-    // filter which skips some months
+    // filter which skips some months.
     $tests[] = array(
       'BYMONTH' => array(12),
       'INTERVAL' => 17,
@@ -734,7 +734,76 @@
       '19981205',
     );
 
+    $tests[] = array(
+      'BYMONTHDAY' => array(1, 3),
+    );
+    $expect[] = array(
+      '19970903',
+      '19971001',
+      '19971003',
+    );
 
+    $tests[] = array(
+      'BYMONTH' => array(1, 3),
+      'BYMONTHDAY' => array(5, 7),
+    );
+    $expect[] = array(
+      '19980105',
+      '19980107',
+      '19980305',
+    );
+
+    $tests[] = array(
+      'BYDAY' => array('TU', 'TH'),
+    );
+    $expect[] = array(
+      '19970902',
+      '19970904',
+      '19970909',
+    );
+
+    $tests[] = array(
+      'BYMONTH' => array(1, 3),
+      'BYDAY' => array('TU', 'TH'),
+    );
+    $expect[] = array(
+      '19980101',
+      '19980106',
+      '19980108',
+    );
+
+    $tests[] = array(
+      'BYMONTHDAY' => array(1, 3),
+      'BYDAY' => array('TU', 'TH'),
+    );
+    $expect[] = array(
+      '19980101',
+      '19980203',
+      '19980303',
+    );
+
+    $tests[] = array(
+      'BYMONTH' => array(1, 3),
+      'BYMONTHDAY' => array(1, 3),
+      'BYDAY' => array('TU', 'TH'),
+    );
+    $expect[] = array(
+      '19980101',
+      '19980303',
+      '20010301',
+    );
+
+    $tests[] = array(
+      'BYHOUR' => array(6, 18),
+      'BYMINUTE' => array(15, 45),
+      'BYSETPOS' => array(3, -3),
+      'DTSTART' => '19970902T090000Z',
+    );
+    $expect[] = array(
+      '19970902T181500Z',
+      '19970903T064500Z',
+      '19970903T181500Z',
+    );
 
     $this->assertRules(
       array(