diff --git a/Framework/DataObjects/inc/MantidDataObjects/EventList.h b/Framework/DataObjects/inc/MantidDataObjects/EventList.h
index 8468f490acd264b76f304bfc51a624c197977e58..ddccb5d7f1319f39c76303c3b711ae32b3a8f4bf 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/EventList.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/EventList.h
@@ -222,6 +222,9 @@ public:
   virtual size_t histogram_size() const;
 
   void compressEvents(double tolerance, EventList *destination);
+  void compressFatEvents(const double tolerance,
+                         const Types::Core::DateAndTime &timeStart,
+                         const double seconds, EventList *destination);
   // get EventType declaration
   void generateHistogram(const MantidVec &X, MantidVec &Y, MantidVec &E,
                          bool skipError = false) const override;
@@ -436,6 +439,12 @@ private:
                                     std::vector<WeightedEventNoTime> &out,
                                     double tolerance);
   template <class T>
+  static void compressFatEventsHelper(
+      const std::vector<T> &events, std::vector<WeightedEvent> &out,
+      const double tolerance, const Mantid::Types::Core::DateAndTime &timeStart,
+      const double seconds);
+
+  template <class T>
   static void histogramForWeightsHelper(const std::vector<T> &events,
                                         const MantidVec &X, MantidVec &Y,
                                         MantidVec &E);
diff --git a/Framework/DataObjects/src/EventList.cpp b/Framework/DataObjects/src/EventList.cpp
index 917b57063dc0a12a74fd1c72b9ed9c7bd5f31a92..c615f3362ffaa59fcafe12ba86154263ecb76bde 100644
--- a/Framework/DataObjects/src/EventList.cpp
+++ b/Framework/DataObjects/src/EventList.cpp
@@ -2,6 +2,7 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidDataObjects/EventWorkspaceMRU.h"
 #include "MantidKernel/DateAndTime.h"
+#include "MantidKernel/DateAndTimeHelpers.h"
 #include "MantidKernel/Exception.h"
 #include "MantidKernel/Logger.h"
 #include "MantidKernel/Unit.h"
@@ -28,7 +29,6 @@ using std::vector;
 
 namespace Mantid {
 namespace DataObjects {
-using Kernel::Exception::NotImplementedError;
 using Types::Core::DateAndTime;
 using Types::Event::TofEvent;
 using namespace Mantid::API;
@@ -1567,6 +1567,87 @@ void EventList::compressEventsParallelHelper(
     out.insert(out.end(), outputs[thread].begin(), outputs[thread].end());
 }
 
+template <class T>
+inline void EventList::compressFatEventsHelper(
+    const std::vector<T> &events, std::vector<WeightedEvent> &out,
+    const double tolerance, const Types::Core::DateAndTime &timeStart,
+    const double seconds) {
+  // Clear the output. We can't know ahead of time how much space to reserve :(
+  out.clear();
+  // We will make a starting guess of 1/20th of the number of input events.
+  out.reserve(events.size() / 20);
+
+  // The last TOF to which we are comparing.
+  double lastTof = std::numeric_limits<double>::lowest();
+  // For getting an accurate average TOF
+  double totalTof = 0;
+
+  // pulsetime bin information - stored as int nanoseconds because it
+  // implementation type for DateAndTime object
+  const double SEC_TO_NANO = 1.e9;
+  const int64_t PULSETIME_TOL = static_cast<int64_t>(seconds * SEC_TO_NANO);
+
+  // pusletime information
+  DateAndTime timeRight = timeStart + PULSETIME_TOL; // right boundary <
+  std::vector<DateAndTime> pulsetimes; // all the times for new event
+
+  // Carrying weight and error
+  double weight = 0;
+  double errorSquared = 0;
+
+  // move up to first event that has a large enough pusletime
+  auto it = events.cbegin();
+  for (; it != events.cend(); ++it) {
+    if (it->m_pulsetime >= timeStart)
+      break;
+  }
+  // loop through events and accumulate weight
+  for (; it != events.cend(); ++it) {
+    if ((it->m_pulsetime < timeRight) && (it->m_tof - lastTof) <= tolerance) {
+      // Carry the error and weight
+      weight += it->weight();
+      errorSquared += it->errorSquared();
+      // Track the average tof
+      totalTof += it->m_tof;
+      // Accumulate the pulse times
+      pulsetimes.push_back(it->m_pulsetime);
+    } else {
+      // We exceeded the tolerance
+      if (!pulsetimes.empty()) {
+        // Create a new event with the average TOF and summed weights and
+        // squared errors.
+        out.emplace_back(totalTof / static_cast<double>(pulsetimes.size()),
+                         Kernel::DateAndTimeHelpers::averageSorted(pulsetimes),
+                         weight, errorSquared);
+      }
+      // Start a new combined object
+      totalTof = it->m_tof;
+      weight = it->weight();
+      errorSquared = it->errorSquared();
+      lastTof = it->m_tof;
+      timeRight += PULSETIME_TOL;
+      pulsetimes.clear();
+      pulsetimes.push_back(it->m_pulsetime);
+    }
+  }
+
+  // Put the last event in there too.
+  if (!pulsetimes.empty()) {
+    // Create a new event with the average TOF and summed weights and squared
+    // errors.
+    out.emplace_back(totalTof / static_cast<double>(pulsetimes.size()),
+                     Kernel::DateAndTimeHelpers::averageSorted(pulsetimes),
+                     weight, errorSquared);
+  }
+
+  // If you have over-allocated by more than 5%, reduce the size.
+  size_t excess_limit = out.size() / 20;
+  if ((out.capacity() - out.size()) > excess_limit) {
+    // Note: This forces a copy!
+    std::vector<WeightedEvent>(out).swap(out);
+  }
+}
+
 // --------------------------------------------------------------------------
 /** Compress the event list by grouping events with the same
  * TOF (within a given tolerance). PulseTime is ignored.
@@ -1628,6 +1709,41 @@ void EventList::compressEvents(double tolerance, EventList *destination) {
   destination->clearUnused();
 }
 
+void EventList::compressFatEvents(
+    const double tolerance, const Mantid::Types::Core::DateAndTime &timeStart,
+    const double seconds, EventList *destination) {
+  switch (eventType) {
+  case WEIGHTED_NOTIME:
+    throw std::invalid_argument(
+        "Cannot compress events that do not have pulsetime");
+  case TOF:
+    this->sortPulseTimeTOF();
+    compressFatEventsHelper(this->events, destination->weightedEvents,
+                            tolerance, timeStart, seconds);
+    break;
+  case WEIGHTED:
+    this->sortPulseTimeTOF();
+    if (destination == this) {
+      // Put results in a temp output
+      std::vector<WeightedEvent> out;
+      compressFatEventsHelper(this->weightedEvents, out, tolerance, timeStart,
+                              seconds);
+      // Put it back
+      this->weightedEvents.swap(out);
+    } else {
+      compressFatEventsHelper(this->weightedEvents, destination->weightedEvents,
+                              tolerance, timeStart, seconds);
+    }
+    break;
+  }
+  // In all cases, you end up WEIGHTED_NOTIME.
+  destination->eventType = WEIGHTED;
+  // The sort is still valid!
+  destination->order = PULSETIMETOF_SORT;
+  // Empty out storage for vectors that are now unused.
+  destination->clearUnused();
+}
+
 // --------------------------------------------------------------------------
 /** Utility function:
  * Returns the iterator into events of the first TofEvent with
diff --git a/Framework/DataObjects/test/EventListTest.h b/Framework/DataObjects/test/EventListTest.h
index 93b909c7efff214949b1ce4af59d0d3736aa8550..233b33800764ee0d802f4578d2fe61361120acaf 100644
--- a/Framework/DataObjects/test/EventListTest.h
+++ b/Framework/DataObjects/test/EventListTest.h
@@ -1417,18 +1417,19 @@ public:
     // Go through each possible EventType (except the no-time one) as the input
     for (int this_type = 0; this_type < 3; this_type++) {
       EventType curType = static_cast<EventType>(this_type);
+      // Since input data has varying pulse time, and same TOF on all events.
+      // Nothing interesting happens here.
+      if (curType == WEIGHTED_NOTIME) {
+        continue;
+      }
+
       EventList el = this->fake_uniform_pulse_data(curType, 1);
       el.switchTo(curType);
 
       const double tofFactor = 1; // L1 / (L1 + L2)
       const double tofShift = 0;
-      if (curType == WEIGHTED_NOTIME) {
-        TS_ASSERT_THROWS_NOTHING(el.sortTimeAtSample(tofFactor, tofShift));
-        // Since input data has varying pulse time, and same TOF on all events.
-        // Nothing interesting happens here.
-      } else {
-        TS_ASSERT_THROWS_NOTHING(el.sortTimeAtSample(tofFactor, tofShift));
-
+      TS_ASSERT_THROWS_NOTHING(el.sortTimeAtSample(tofFactor, tofShift));
+      if (curType != WEIGHTED_NOTIME) {
         for (size_t i = 1; i < el.getNumberEvents(); i++) {
           TSM_ASSERT_LESS_THAN_EQUALS(this_type, el.getEvent(i - 1).pulseTime(),
                                       el.getEvent(i).pulseTime());
@@ -1440,13 +1441,12 @@ public:
   void test_sortByTimeAtSample_random_tof_time() {
     for (int this_type = 0; this_type < 3; this_type++) {
       EventType curType = static_cast<EventType>(this_type);
+      if (curType == WEIGHTED_NOTIME)
+        continue;
+
       EventList el = this->fake_random_tof_constant_pulse_data(curType, 10);
       el.switchTo(curType);
 
-      if (curType == WEIGHTED_NOTIME) {
-        continue;
-      }
-
       const double tofFactor = 1; // L1 / (L1 + L2)
       const double tofShift = 0;
 
@@ -2040,6 +2040,45 @@ public:
     }   // starting event type
   }
 
+  void test_compressFatEvents() {
+    // no pulse time should throw an exception
+    EventList el_notime_output;
+    EventList el_notime = this->fake_data(WEIGHTED_NOTIME);
+    TS_ASSERT_THROWS(el_notime.compressFatEvents(10., DateAndTime(0), 10.,
+                                                 &el_notime_output),
+                     std::invalid_argument);
+
+    // integration range
+    const double XMIN = 0.;
+    const double XMAX = 1.e7;
+
+    // regular events should compress decently well
+    EventList el_output;
+    this->fake_uniform_data_weights(TOF);
+    TS_ASSERT_THROWS_NOTHING(
+        el.compressFatEvents(20000., el.getPulseTimeMin(), 5., &el_output));
+    TS_ASSERT_EQUALS(el_output.getNumberEvents(), 400);
+    TS_ASSERT_EQUALS(el_output.integrate(XMIN, XMAX, true),
+                     el.integrate(XMIN, XMAX, true));
+
+    // weighted events with time is the main use case
+    EventList el_weight_output;
+    this->fake_uniform_data_weights(WEIGHTED);
+    TS_ASSERT_THROWS_NOTHING(el.compressFatEvents(20000., el.getPulseTimeMin(),
+                                                  5., &el_weight_output));
+    TS_ASSERT_EQUALS(el_weight_output.getNumberEvents(), 400);
+    TS_ASSERT_EQUALS(el_weight_output.integrate(XMIN, XMAX, true),
+                     el.integrate(XMIN, XMAX, true));
+
+    // change the start time to see that events don't make it in
+    el_weight_output.clear();
+    // previous run's this->fake_uniform_data_weights(WEIGHTED);
+    TS_ASSERT_THROWS_NOTHING(el.compressFatEvents(20000., el.getPulseTimeMax(),
+                                                  5., &el_weight_output));
+    TS_ASSERT_EQUALS(el_weight_output.getNumberEvents(), 1);
+    TS_ASSERT_DELTA(el_weight_output.integrate(XMIN, XMAX, true), 2., .0001);
+  }
+
   void test_getEventsFrom() {
     std::vector<TofEvent> *rel;
     TS_ASSERT_THROWS_NOTHING(getEventsFrom(el, rel));
@@ -2283,15 +2322,37 @@ public:
   // Mocking functions
   //==================================================================================
 
-  EventList fake_data() {
+  EventList fake_data(EventType eventType = TOF) {
     // Clear the list
     el = EventList();
+    if (eventType != TOF)
+      el.switchTo(eventType);
+
     // Create some mostly-reasonable fake data.
     srand(1234); // Fixed random seed
-    for (int i = 0; i < NUMEVENTS; i++) {
-      // Random tof up to 10 ms
-      // Random pulse time up to 1000
-      el += TofEvent(1e7 * (rand() * 1.0 / RAND_MAX), rand() % 1000);
+    switch (eventType) {
+    case TOF:
+      for (int i = 0; i < NUMEVENTS; i++) {
+        // Random tof up to 10 ms
+        // Random pulse time up to 1000
+        el += TofEvent(1e7 * (rand() * 1.0 / RAND_MAX), rand() % 1000);
+      }
+      break;
+    case WEIGHTED:
+      for (int i = 0; i < NUMEVENTS; i++) {
+        // Random tof up to 10 ms
+        // Random pulse time up to 1000
+        el += WeightedEvent(
+            TofEvent(1e7 * (rand() * 1.0 / RAND_MAX), rand() % 1000));
+      }
+      break;
+    case WEIGHTED_NOTIME:
+      for (int i = 0; i < NUMEVENTS; i++) {
+        // Random tof up to 10 ms
+        // Random pulse time up to 1000
+        el += TofEvent(1e7 * (rand() * 1.0 / RAND_MAX), rand() % 1000);
+      }
+      break;
     }
     return el;
   }
@@ -2313,6 +2374,8 @@ public:
            pulse_time += BIN_DELTA / events_per_bin) {
         el += WeightedEvent(TofEvent(100, static_cast<size_t>(pulse_time)));
       }
+    } else {
+      throw std::runtime_error("not implemented: fake_uniform_pulse_data");
     }
     return el;
   }
@@ -2330,6 +2393,9 @@ public:
         // Random tof up to 10 ms
         el += WeightedEvent(TofEvent(1e7 * (rand() * 1.0 / RAND_MAX), 0));
       }
+    } else {
+      throw std::runtime_error(
+          "not implemented: fake_random_tof_constant_pulse_data");
     }
     return el;
   }
@@ -2358,15 +2424,27 @@ public:
   }
 
   /** Create a uniform event list with each event weight of 2.0, error 2.5 */
-  void fake_uniform_data_weights() {
+  void fake_uniform_data_weights(EventType eventType = WEIGHTED) {
     // Clear the list
     el = EventList();
-    el.switchTo(WEIGHTED);
+    if (eventType != TOF)
+      el.switchTo(WEIGHTED);
+
     // Create some mostly-reasonable fake data.
     srand(1234); // Fixed random seed
+    int64_t pulsetime = 0;
+    // 10^6 nanoseconds for pulse time delta
+    const int64_t PULSETIME_DELTA = static_cast<int64_t>(BIN_DELTA / 1000);
     for (double tof = 100; tof < MAX_TOF; tof += BIN_DELTA / 2) {
+      // add some jitter into the pulse time with rand
+      pulsetime = 10000 * (static_cast<int64_t>(tof) / PULSETIME_DELTA) +
+                  (rand() % 1000);
       // tof steps of 5 microseconds, starting at 100 ns, up to 20 msec
-      el += WeightedEvent(tof, rand() % 1000, 2.0, 2.5 * 2.5);
+      if (eventType == TOF) {
+        el += TofEvent(tof, pulsetime);
+      } else if (eventType == WEIGHTED) {
+        el += WeightedEvent(tof, pulsetime, 2.0, 2.5 * 2.5);
+      }
     }
   }