diff --git a/Framework/DataHandling/CMakeLists.txt b/Framework/DataHandling/CMakeLists.txt
index e83eab36a955123e3b1c5c66f7c31a5357e716e4..59fc757e04b17587fdbb9cb0fbd904756e39a186 100644
--- a/Framework/DataHandling/CMakeLists.txt
+++ b/Framework/DataHandling/CMakeLists.txt
@@ -107,6 +107,7 @@ set ( SRC_FILES
 	src/ModifyDetectorDotDatFile.cpp
 	src/MoveInstrumentComponent.cpp
 	src/NexusTester.cpp
+	src/PatchBBY.cpp
 	src/PDLoadCharacterizations.cpp
 	src/ProcessDasNexusLog.cpp
 	src/RawFileInfo.cpp
@@ -263,6 +264,7 @@ set ( INC_FILES
 	inc/MantidDataHandling/ModifyDetectorDotDatFile.h
 	inc/MantidDataHandling/MoveInstrumentComponent.h
 	inc/MantidDataHandling/NexusTester.h
+	inc/MantidDataHandling/PatchBBY.h
 	inc/MantidDataHandling/PDLoadCharacterizations.h
 	inc/MantidDataHandling/ProcessDasNexusLog.h
 	inc/MantidDataHandling/RawFileInfo.h
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadANSTOHelper.h b/Framework/DataHandling/inc/MantidDataHandling/LoadANSTOHelper.h
index 3b0e7bbe2460f938f41c6919904f1da986ccdef0..5b2849f9f669dbbd435c89629b25d754c65839c6 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadANSTOHelper.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadANSTOHelper.h
@@ -53,25 +53,29 @@ protected:
   // fields
   const std::vector<bool> &m_roi;
   const size_t m_stride;
+  // number of frames
+  size_t m_frames;
   // tof correction
   const double m_period;
   const double m_phase;
   // boundaries
   const double m_tofMinBoundary;
   const double m_tofMaxBoundary;
+  const double m_timeMinBoundary;
+  const double m_timeMaxBoundary;
 
   // methods
-  virtual void endOfFrameImpl() = 0;
   virtual void addEventImpl(size_t id, double tof) = 0;
 
 public:
   // construction
   EventProcessor(const std::vector<bool> &roi, const size_t stride,
                  const double period, const double phase,
-                 const double tofMinBoundary, const double tofMaxBoundary);
+                 const double tofMinBoundary, const double tofMaxBoundary,
+                 const double timeMinBoundary, const double timeMaxBoundary);
 
   // methods
-  void endOfFrame();
+  void newFrame();
   void addEvent(size_t x, size_t y, double tof);
 };
 
@@ -79,21 +83,19 @@ class EventCounter : public EventProcessor {
 protected:
   // fields
   std::vector<size_t> &m_eventCounts;
-  // number of frames
-  size_t m_numFrames;
   // tof
   double m_tofMin;
   double m_tofMax;
 
   // methods
-  void endOfFrameImpl() override;
-  void addEventImpl(size_t id, double tof) override;
+  virtual void addEventImpl(size_t id, double tof); // override
 
 public:
   // construction
   EventCounter(const std::vector<bool> &roi, const size_t stride,
                const double period, const double phase,
                const double tofMinBoundary, const double tofMaxBoundary,
+               const double timeMinBoundary, const double timeMaxBoundary,
                std::vector<size_t> &eventCounts);
 
   // properties
@@ -108,14 +110,14 @@ protected:
   std::vector<EventVector_pt> &m_eventVectors;
 
   // methods
-  void endOfFrameImpl() override;
-  void addEventImpl(size_t id, double tof) override;
+  virtual void addEventImpl(size_t id, double tof) override;
 
 public:
   // construction
   EventAssigner(const std::vector<bool> &roi, const size_t stride,
                 const double period, const double phase,
                 const double tofMinBoundary, const double tofMaxBoundary,
+                const double timeMinBoundary, const double timeMaxBoundary,
                 std::vector<EventVector_pt> &eventVectors);
 };
 
@@ -135,6 +137,7 @@ public:
   void *handle() const;
 
   // methods
+  void close();
   bool read(void *buffer, uint32_t size);
   bool seek(int64_t offset, int whence, int64_t *newPosition = NULL);
 };
@@ -172,6 +175,11 @@ struct EntryHeader {
   char DeviceMinorNumber[8];
   // cppcheck-suppress unusedStructMember
   char FilenamePrefix[155];
+
+  // methods
+  void writeChecksum();
+  void writeFileSize(int64_t value);
+  int64_t readFileSize();
 };
 
 class File {
@@ -205,6 +213,7 @@ private:
 public:
   // construction
   File(const std::string &path);
+  void close();
 
   // properties
   bool good() const;
@@ -219,6 +228,10 @@ public:
   bool skip(uint64_t offset);
   size_t read(void *dst, size_t size);
   int read_byte();
+
+  // helpers
+  static bool append(const std::string &path, const std::string &name,
+                     const void *buffer, size_t size);
 };
 
 } // Tar
@@ -226,4 +239,4 @@ public:
 } // DataHandling
 } // Mantid
 
-#endif // DATAHANDING_ANSTO_H_
\ No newline at end of file
+#endif // DATAHANDING_ANSTO_H_
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadBBY.h b/Framework/DataHandling/inc/MantidDataHandling/LoadBBY.h
index 4ac247b96ee12a2e86497ba6db5ca8f3d7bcc52e..bab73f346e6a722f3731e9dbdf68eed378178c95 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadBBY.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadBBY.h
@@ -78,9 +78,9 @@ public:
   // description
   int version() const override { return 1; }
   const std::string name() const override { return "LoadBBY"; }
-  const std::string category() const override { return "DataHandling\\Nexus"; }
+  virtual const std::string category() const { return "DataHandling"; }
   const std::string summary() const override {
-    return "Loads a BilBy data file into an workspace.";
+    return "Loads a BilBy data file into a workspace.";
   }
 
   // returns a confidence value that this algorithm can load a specified file
@@ -115,4 +115,4 @@ private:
 } // DataHandling
 } // Mantid
 
-#endif // DATAHANDING_LOADBBY_H_
\ No newline at end of file
+#endif // DATAHANDING_LOADBBY_H_
diff --git a/Framework/DataHandling/inc/MantidDataHandling/PatchBBY.h b/Framework/DataHandling/inc/MantidDataHandling/PatchBBY.h
new file mode 100644
index 0000000000000000000000000000000000000000..272694b6d58d2e23d9b16873b2e262166523bd86
--- /dev/null
+++ b/Framework/DataHandling/inc/MantidDataHandling/PatchBBY.h
@@ -0,0 +1,70 @@
+#ifndef DATAHANDING_PATCHBBY_H_
+#define DATAHANDING_PATCHBBY_H_
+
+//---------------------------------------------------
+// Includes
+//---------------------------------------------------
+
+#include "MantidAPI/IFileLoader.h"
+#include "MantidGeometry/Instrument.h"
+#include "MantidDataObjects/EventWorkspace.h"
+#include "MantidNexus/NexusClasses.h"
+#include "LoadANSTOHelper.h"
+
+namespace Mantid {
+namespace DataHandling {
+/**
+Patches a Bilby data file. Implements API::Algorithm and its file check methods
+to recognise a file as the one containing Bilby data.
+
+@author David Mannicke (ANSTO), Anders Markvardsen (ISIS), Roman Tolchenov
+(Tessella plc)
+@date 22/01/2016
+
+Copyright &copy; 2010 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
+National Laboratory & European Spallation Source
+
+This file is part of Mantid.
+
+Mantid is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
+
+Mantid is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+File change history is stored at: <https://github.com/mantidproject/mantid>
+Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+
+class DLLExport PatchBBY : public API::Algorithm {
+public:
+  // construction
+  PatchBBY() {}
+  virtual ~PatchBBY() {}
+
+  // description
+  virtual int version() const override { return 1; }
+  virtual const std::string name() const override { return "PatchBBY"; }
+  virtual const std::string category() const override { return "DataHandling"; }
+  virtual const std::string summary() const override {
+    return "Patches a BilBy data file.";
+  }
+
+protected:
+  // initialisation
+  virtual void init() override;
+  // execution
+  virtual void exec() override;
+};
+
+} // DataHandling
+} // Mantid
+
+#endif // DATAHANDING_PATCHBBY_H_
diff --git a/Framework/DataHandling/src/LoadANSTOHelper.cpp b/Framework/DataHandling/src/LoadANSTOHelper.cpp
index a7fc77bad17d636e6316edddb2f1876aae068968..9749fe7917bfac10fab72ab73fd959be6766de0c 100644
--- a/Framework/DataHandling/src/LoadANSTOHelper.cpp
+++ b/Framework/DataHandling/src/LoadANSTOHelper.cpp
@@ -8,6 +8,8 @@
 #include "MantidGeometry/Objects/ShapeFactory.h"
 #include "MantidNexus/NexusClasses.h"
 
+#include <numeric>
+
 namespace Mantid {
 namespace DataHandling {
 namespace ANSTO {
@@ -51,10 +53,14 @@ void ProgressTracker::complete() {
 EventProcessor::EventProcessor(const std::vector<bool> &roi,
                                const size_t stride, const double period,
                                const double phase, const double tofMinBoundary,
-                               const double tofMaxBoundary)
-    : m_roi(roi), m_stride(stride), m_period(period), m_phase(phase),
-      m_tofMinBoundary(tofMinBoundary), m_tofMaxBoundary(tofMaxBoundary) {}
-void EventProcessor::endOfFrame() { endOfFrameImpl(); }
+                               const double tofMaxBoundary,
+                               const double timeMinBoundary,
+                               const double timeMaxBoundary)
+    : m_roi(roi), m_stride(stride), m_frames(0), m_period(period),
+      m_phase(phase), m_tofMinBoundary(tofMinBoundary),
+      m_tofMaxBoundary(tofMaxBoundary), m_timeMinBoundary(timeMinBoundary),
+      m_timeMaxBoundary(timeMaxBoundary) {}
+void EventProcessor::newFrame() { m_frames++; }
 void EventProcessor::addEvent(size_t x, size_t y, double tof) {
   // tof correction
   if (m_period > 0.0) {
@@ -66,16 +72,27 @@ void EventProcessor::addEvent(size_t x, size_t y, double tof) {
   }
 
   // check if event is in valid range
-  if ((y < m_stride) && (m_tofMinBoundary <= tof) &&
-      (tof <= m_tofMaxBoundary)) {
 
-    // detector id
-    size_t id = m_stride * x + y;
+  // frame boundary
+  double frameTime =
+      (static_cast<double>(m_frames) * m_period) * 1e-6; // in seconds
+  if ((frameTime < m_timeMinBoundary) || (frameTime > m_timeMaxBoundary))
+    return;
 
-    // check if neutron is in region of intreset
-    if (m_roi[id])
-      addEventImpl(id, tof);
-  }
+  // ToF boundary
+  if ((tof < m_tofMinBoundary) && (tof > m_tofMaxBoundary))
+    return;
+
+  // detector id
+  size_t id = m_stride * x + y;
+
+  // image size
+  if ((y >= m_stride) || (id >= m_roi.size()))
+    return;
+
+  // check if neutron is in region of intreset
+  if (m_roi[id])
+    addEventImpl(id, tof);
 }
 
 // EventCounter
@@ -83,20 +100,20 @@ EventCounter::EventCounter(const std::vector<bool> &roi, const size_t stride,
                            const double period, const double phase,
                            const double tofMinBoundary,
                            const double tofMaxBoundary,
+                           const double timeMinBoundary,
+                           const double timeMaxBoundary,
                            std::vector<size_t> &eventCounts)
-    : EventProcessor(roi, stride, period, phase, tofMinBoundary,
-                     tofMaxBoundary),
-      m_eventCounts(eventCounts), m_numFrames(0),
-      m_tofMin(std::numeric_limits<double>::max()),
+    : EventProcessor(roi, stride, period, phase, tofMinBoundary, tofMaxBoundary,
+                     timeMinBoundary, timeMaxBoundary),
+      m_eventCounts(eventCounts), m_tofMin(std::numeric_limits<double>::max()),
       m_tofMax(std::numeric_limits<double>::min()) {}
-size_t EventCounter::numFrames() const { return m_numFrames; }
+size_t EventCounter::numFrames() const { return m_frames; }
 double EventCounter::tofMin() const {
   return m_tofMin <= m_tofMax ? m_tofMin : 0.0;
 }
 double EventCounter::tofMax() const {
   return m_tofMin <= m_tofMax ? m_tofMax : 0.0;
 }
-void EventCounter::endOfFrameImpl() { m_numFrames++; }
 void EventCounter::addEventImpl(size_t id, double tof) {
   if (m_tofMin > tof)
     m_tofMin = tof;
@@ -111,13 +128,12 @@ EventAssigner::EventAssigner(const std::vector<bool> &roi, const size_t stride,
                              const double period, const double phase,
                              const double tofMinBoundary,
                              const double tofMaxBoundary,
+                             const double timeMinBoundary,
+                             const double timeMaxBoundary,
                              std::vector<EventVector_pt> &eventVectors)
-    : EventProcessor(roi, stride, period, phase, tofMinBoundary,
-                     tofMaxBoundary),
+    : EventProcessor(roi, stride, period, phase, tofMinBoundary, tofMaxBoundary,
+                     timeMinBoundary, timeMaxBoundary),
       m_eventVectors(eventVectors) {}
-void EventAssigner::endOfFrameImpl() {
-  // ignore
-}
 void EventAssigner::addEventImpl(size_t id, double tof) {
   m_eventVectors[id]->push_back(tof);
 }
@@ -128,11 +144,12 @@ FastReadOnlyFile::FastReadOnlyFile(const char *filename) {
   m_handle = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
                          OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 }
-FastReadOnlyFile::~FastReadOnlyFile() {
+FastReadOnlyFile::~FastReadOnlyFile() { close(); }
+void *FastReadOnlyFile::handle() const { return m_handle; }
+void FastReadOnlyFile::close() {
   CloseHandle(m_handle);
   m_handle = NULL;
 }
-void *FastReadOnlyFile::handle() const { return m_handle; }
 bool FastReadOnlyFile::read(void *buffer, uint32_t size) {
   DWORD bytesRead;
   return (FALSE != ReadFile(m_handle, buffer, size, &bytesRead, NULL)) &&
@@ -146,11 +163,12 @@ bool FastReadOnlyFile::seek(int64_t offset, int whence, int64_t *newPosition) {
 FastReadOnlyFile::FastReadOnlyFile(const char *filename) {
   m_handle = fopen(filename, "rb");
 }
-FastReadOnlyFile::~FastReadOnlyFile() {
+FastReadOnlyFile::~FastReadOnlyFile() { close(); }
+void *FastReadOnlyFile::handle() const { return m_handle; }
+void FastReadOnlyFile::close() {
   fclose(m_handle);
   m_handle = nullptr;
 }
-void *FastReadOnlyFile::handle() const { return m_handle; }
 bool FastReadOnlyFile::read(void *buffer, uint32_t size) {
   return 1 == fread(buffer, static_cast<size_t>(size), 1, m_handle);
 }
@@ -163,10 +181,34 @@ bool FastReadOnlyFile::seek(int64_t offset, int whence, int64_t *newPosition) {
 
 namespace Tar {
 
-template <size_t N> int64_t octalToInt(char(&str)[N]) {
+void EntryHeader::writeChecksum() {
+  memset(Checksum, ' ', sizeof(Checksum));
+  size_t value = std::accumulate(
+      (const char *)this, (const char *)this + sizeof(EntryHeader), (size_t)0);
+
+  std::ostringstream buffer;
+
+  buffer << std::oct << std::setfill('0')
+         << std::setw(static_cast<int>(sizeof(Checksum)) - 1) << value;
+  std::string string = buffer.str();
+
+  std::copy(string.cbegin(), string.cend(), Checksum);
+  Checksum[string.size()] = 0;
+}
+void EntryHeader::writeFileSize(int64_t value) {
+  std::ostringstream buffer;
+
+  buffer << std::oct << std::setfill('0')
+         << std::setw(static_cast<int>(sizeof(FileSize)) - 1) << value;
+  std::string string = buffer.str();
+
+  std::copy(string.cbegin(), string.cend(), FileSize);
+  FileSize[string.size()] = 0;
+}
+int64_t EntryHeader::readFileSize() {
   int64_t result = 0;
-  char *p = str;
-  for (size_t n = N; n > 1; --n) { // last character is '\0'
+  const char *p = FileSize;
+  for (size_t n = sizeof(FileSize) - 1; n != 0; --n) { // last character is '\0'
     char c = *p++;
     if (('0' <= c) && (c <= '9'))
       result = result * 8 + (c - '0');
@@ -195,7 +237,7 @@ File::File(const std::string &path)
 
     FileInfo fileInfo;
     fileInfo.Offset = position;
-    fileInfo.Size = octalToInt(header.FileSize);
+    fileInfo.Size = header.readFileSize();
 
     if (header.TypeFlag == TarTypeFlag_NormalFile) {
       m_fileNames.push_back(fileName);
@@ -209,6 +251,17 @@ File::File(const std::string &path)
     m_good &= m_file.seek(fileInfo.Size + offset, SEEK_CUR);
   }
 }
+void File::close() {
+  m_good = false;
+  m_file.close();
+  m_fileNames.clear();
+  m_fileInfos.clear();
+  m_selected = static_cast<size_t>(-1);
+  m_position = 0;
+  m_size = 0;
+  m_bufferPosition = 0;
+  m_bufferAvailable = 0;
+}
 
 // properties
 bool File::good() const { return m_good; }
@@ -330,8 +383,96 @@ int File::read_byte() {
   m_position++;
   return m_buffer[m_bufferPosition++];
 }
+bool File::append(const std::string &path, const std::string &name,
+                  const void *buffer, size_t size) {
+  std::unique_ptr<FILE, decltype(&fclose)> handle(fopen(path.c_str(), "rb+"),
+                                                  fclose);
+
+  bool good = handle != NULL;
+  int64_t lastHeaderPosition = 0;
+  int64_t targetPosition = -1;
+
+  while (good) {
+    EntryHeader header;
+    int64_t position;
+
+    lastHeaderPosition = static_cast<int64_t>(ftell(handle.get()));
+
+    good &= 1 == fread(&header, sizeof(EntryHeader), 1, handle.get());
+    good &= 0 == fseek(handle.get(), 512 - sizeof(EntryHeader), SEEK_CUR);
+    good &= 0 <= (position = static_cast<int64_t>(ftell(handle.get())));
+
+    if (!good)
+      return false;
+
+    std::string fileName(header.FileName);
+    if (fileName.length() == 0)
+      break;
+
+    if (fileName.compare(name) == 0)
+      targetPosition = lastHeaderPosition;
+    else if (targetPosition != -1)
+      throw std::runtime_error(
+          "format exception"); // it has to be the last file in the archive
+
+    FileInfo fileInfo;
+    fileInfo.Offset = position;
+    fileInfo.Size = header.readFileSize();
+
+    size_t offset = static_cast<size_t>(fileInfo.Size % 512);
+    if (offset != 0)
+      offset = 512 - offset;
+
+    good &= 0 == fseek(handle.get(), static_cast<long>(fileInfo.Size + offset),
+                       SEEK_CUR);
+  }
+
+  if (!good)
+    return false;
+
+  if (targetPosition == -1)
+    targetPosition = lastHeaderPosition;
+
+  // empty buffer
+  char padding[512];
+  memset(padding, 0, 512);
+
+  // prepare new header
+  EntryHeader header;
+  memset(&header, 0, sizeof(EntryHeader));
+  memcpy(header.FileName, name.c_str(), name.size());
+  memset(header.FileMode, '0', sizeof(header.FileMode) - 1);
+  memset(header.OwnerUserID, '0', sizeof(header.OwnerUserID) - 1);
+  memset(header.OwnerGroupID, '0', sizeof(header.OwnerGroupID) - 1);
+  memset(header.LastModification, '0', sizeof(header.LastModification) - 1);
+
+  header.TypeFlag = TarTypeFlag_NormalFile;
+  header.writeFileSize(size);
+  header.writeChecksum();
+
+  // write header
+  good &= 0 == fseek(handle.get(), static_cast<long>(targetPosition), SEEK_SET);
+  good &= 1 == fwrite(&header, sizeof(EntryHeader), 1, handle.get());
+  good &= 1 == fwrite(padding, 512 - sizeof(EntryHeader), 1, handle.get());
+
+  // write content
+  good &= 1 == fwrite(buffer, size, 1, handle.get());
+
+  // write padding
+  size_t offset = static_cast<size_t>(size % 512);
+  if (offset != 0) {
+    offset = 512 - offset;
+
+    good &= 1 == fwrite(padding, offset, 1, handle.get());
+  }
+
+  // write final
+  good &= 1 == fwrite(padding, 512, 1, handle.get());
+
+  return good;
+}
 
 } // Tar
 } // ANSTO
 } // DataHandling
-} // Mantid
\ No newline at end of file
+} // Mantid
diff --git a/Framework/DataHandling/src/LoadBBY.cpp b/Framework/DataHandling/src/LoadBBY.cpp
index dbdbdd9d608dd0747d6a5e51f2020b4166a7d898..c46e13ca2e1c8d97accb10d5085f66a8fc49d668 100644
--- a/Framework/DataHandling/src/LoadBBY.cpp
+++ b/Framework/DataHandling/src/LoadBBY.cpp
@@ -13,7 +13,9 @@
 #include "MantidKernel/UnitFactory.h"
 #include "MantidNexus/NexusClasses.h"
 
+#include <Poco/AutoPtr.h>
 #include <Poco/TemporaryFile.h>
+#include <Poco/Util/PropertyFileConfiguration.h>
 
 namespace Mantid {
 namespace DataHandling {
@@ -40,6 +42,9 @@ static char const *const PhaseSlaveStr = "PhaseSlave";
 static char const *const FilterByTofMinStr = "FilterByTofMin";
 static char const *const FilterByTofMaxStr = "FilterByTofMax";
 
+static char const *const FilterByTimeStartStr = "FilterByTimeStart";
+static char const *const FilterByTimeStopStr = "FilterByTimeStop";
+
 using ANSTO::EventVector_pt;
 
 template <typename TYPE>
@@ -48,7 +53,8 @@ void AddSinglePointTimeSeriesProperty(API::LogManager &logManager,
                                       const std::string &name,
                                       const TYPE value) {
   // create time series property and add single value
-  auto p = new Kernel::TimeSeriesProperty<TYPE>(name);
+  Kernel::TimeSeriesProperty<TYPE> *p =
+      new Kernel::TimeSeriesProperty<TYPE>(name);
   p->addValue(time, value);
 
   // add to log manager
@@ -155,14 +161,14 @@ void LoadBBY::init() {
 
   // FilterByTimeStart
   declareProperty(
-      new Kernel::PropertyWithValue<double>("FilterByTimeStart", EMPTY_DBL(),
+      new Kernel::PropertyWithValue<double>(FilterByTimeStartStr, 0.0,
                                             Kernel::Direction::Input),
       "Optional: To only include events after the provided start time, in "
       "seconds (relative to the start of the run).");
 
   // FilterByTimeStop
   declareProperty(
-      new Kernel::PropertyWithValue<double>("FilterByTimeStop", EMPTY_DBL(),
+      new Kernel::PropertyWithValue<double>(FilterByTimeStopStr, EMPTY_DBL(),
                                             Kernel::Direction::Input),
       "Optional: To only include events before the provided stop time, in "
       "seconds (relative to the start of the run).");
@@ -181,8 +187,8 @@ void LoadBBY::init() {
   std::string grpOptional = "Filters";
   setPropertyGroup(FilterByTofMinStr, grpOptional);
   setPropertyGroup(FilterByTofMaxStr, grpOptional);
-  setPropertyGroup("FilterByTimeStart", grpOptional);
-  setPropertyGroup("FilterByTimeStop", grpOptional);
+  setPropertyGroup(FilterByTimeStartStr, grpOptional);
+  setPropertyGroup(FilterByTimeStopStr, grpOptional);
 
   std::string grpPhaseCorrection = "Phase Correction";
   setPropertyGroup(PeriodMasterStr, grpPhaseCorrection);
@@ -210,6 +216,14 @@ void LoadBBY::exec() {
   double tofMinBoundary = getProperty(FilterByTofMinStr);
   double tofMaxBoundary = getProperty(FilterByTofMaxStr);
 
+  double timeMinBoundary = getProperty(FilterByTimeStartStr);
+  double timeMaxBoundary = getProperty(FilterByTimeStopStr);
+
+  if (isEmpty(tofMaxBoundary))
+    tofMaxBoundary = std::numeric_limits<double>::infinity();
+  if (isEmpty(timeMaxBoundary))
+    timeMaxBoundary = std::numeric_limits<double>::infinity();
+
   API::Progress prog(this, 0.0, 1.0, Progress_Total);
   prog.doReport("creating instrument");
 
@@ -291,8 +305,9 @@ void LoadBBY::exec() {
   double shift = -1.0 / 6.0 * periodMaster - periodSlave * phaseSlave / 360.0;
 
   // count total events per pixel to reserve necessary memory
-  ANSTO::EventCounter eventCounter(roi, HISTO_BINS_Y, period, shift,
-                                   tofMinBoundary, tofMaxBoundary, eventCounts);
+  ANSTO::EventCounter eventCounter(
+      roi, HISTO_BINS_Y, period, shift, tofMinBoundary, tofMaxBoundary,
+      timeMinBoundary, timeMaxBoundary, eventCounts);
 
   loadEvents(prog, "loading neutron counts", tarFile, eventCounter);
 
@@ -306,8 +321,8 @@ void LoadBBY::exec() {
     eventList.setSortOrder(DataObjects::PULSETIME_SORT);
     eventList.reserve(eventCounts[i]);
 
-    eventList.setDetectorID(Mantid::detid_t(i));
-    eventList.setSpectrumNo(Mantid::detid_t(i));
+    eventList.setDetectorID(static_cast<detid_t>(i));
+    eventList.setSpectrumNo(static_cast<detid_t>(i));
 
     DataObjects::getEventsFrom(eventList, eventVectors[i]);
 
@@ -315,9 +330,9 @@ void LoadBBY::exec() {
   }
   progTracker.complete();
 
-  ANSTO::EventAssigner eventAssigner(roi, HISTO_BINS_Y, period, shift,
-                                     tofMinBoundary, tofMaxBoundary,
-                                     eventVectors);
+  ANSTO::EventAssigner eventAssigner(
+      roi, HISTO_BINS_Y, period, shift, tofMinBoundary, tofMaxBoundary,
+      timeMinBoundary, timeMaxBoundary, eventVectors);
 
   loadEvents(prog, "loading neutron events", tarFile, eventAssigner);
 
@@ -469,6 +484,9 @@ std::vector<bool> LoadBBY::createRoiVector(const std::string &maskfile) {
 Geometry::Instrument_sptr
 LoadBBY::createInstrument(ANSTO::Tar::File &tarFile,
                           InstrumentInfo &instrumentInfo) {
+
+  const double toMeters = 1.0 / 1000;
+
   instrumentInfo.bm_counts = 0;
   instrumentInfo.att_pos = 0;
 
@@ -491,12 +509,13 @@ LoadBBY::createInstrument(ANSTO::Tar::File &tarFile,
   instrumentInfo.D_curtainu_value = 0.3947;
   instrumentInfo.D_curtaind_value = 0.3978;
 
-  // extract hdf file
-  int64_t fileSize = 0;
+  // extract log and hdf file
   const std::vector<std::string> &files = tarFile.files();
-  for (const auto &file : files)
-    if (file.rfind(".hdf") == file.length() - 4) {
-      tarFile.select(file.c_str());
+
+  int64_t fileSize = 0;
+  for (auto itr = files.begin(); itr != files.end(); ++itr)
+    if (itr->rfind(".hdf") == itr->length() - 4) {
+      tarFile.select(itr->c_str());
       fileSize = tarFile.selected_size();
       break;
     }
@@ -518,7 +537,6 @@ LoadBBY::createInstrument(ANSTO::Tar::File &tarFile,
 
       float tmp_float;
       int32_t tmp_int32 = 0;
-      const double toMeters = 1.0 / 1000;
 
       if (loadNXDataSet(entry, "monitor/bm1_counts", tmp_int32))
         instrumentInfo.bm_counts = tmp_int32;
@@ -561,6 +579,67 @@ LoadBBY::createInstrument(ANSTO::Tar::File &tarFile,
     }
   }
 
+  // patching
+  std::string logContent;
+  for (auto itr = files.begin(); itr != files.end(); ++itr)
+    if (itr->compare("History.log") == 0) {
+      tarFile.select(itr->c_str());
+      logContent.resize(tarFile.selected_size());
+      tarFile.read(&logContent[0], logContent.size());
+      break;
+    }
+
+  if (logContent.size() > 0) {
+    std::istringstream data(logContent);
+    Poco::AutoPtr<Poco::Util::PropertyFileConfiguration> conf(
+        new Poco::Util::PropertyFileConfiguration(data));
+
+    if (conf->hasProperty("bm1_counts"))
+      instrumentInfo.bm_counts = conf->getInt("bm1_counts");
+    if (conf->hasProperty("att_pos"))
+      instrumentInfo.att_pos =
+          static_cast<int32_t>(conf->getDouble("att_pos") + 0.5f);
+
+    if (conf->hasProperty("master_chopper_freq"))
+      instrumentInfo.period_master =
+          1.0 / conf->getDouble("master_chopper_freq") * 1.0e6;
+    if (conf->hasProperty("t0_chopper_freq"))
+      instrumentInfo.period_slave =
+          1.0 / conf->getDouble("t0_chopper_freq") * 1.0e6;
+    if (conf->hasProperty("t0_chopper_phase"))
+      instrumentInfo.phase_slave = conf->getDouble("t0_chopper_phase");
+
+    if (conf->hasProperty("L2_det"))
+      instrumentInfo.L2_det_value = conf->getDouble("L2_det") * toMeters;
+    if (conf->hasProperty("Ltof_det"))
+      instrumentInfo.L1_chopper_value =
+          conf->getDouble("Ltof_det") * toMeters - instrumentInfo.L2_det_value;
+    // if (conf->hasProperty("L1"))
+    //  instrumentInfo.L1_source_value = conf->getDouble("L1") * toMeters;
+
+    if (conf->hasProperty("L2_curtainl"))
+      instrumentInfo.L2_curtainl_value =
+          conf->getDouble("L2_curtainl") * toMeters;
+    if (conf->hasProperty("L2_curtainr"))
+      instrumentInfo.L2_curtainr_value =
+          conf->getDouble("L2_curtainr") * toMeters;
+    if (conf->hasProperty("L2_curtainu"))
+      instrumentInfo.L2_curtainu_value =
+          conf->getDouble("L2_curtainu") * toMeters;
+    if (conf->hasProperty("L2_curtaind"))
+      instrumentInfo.L2_curtaind_value =
+          conf->getDouble("L2_curtaind") * toMeters;
+
+    if (conf->hasProperty("curtainl"))
+      instrumentInfo.D_curtainl_value = conf->getDouble("curtainl") * toMeters;
+    if (conf->hasProperty("curtainr"))
+      instrumentInfo.D_curtainr_value = conf->getDouble("curtainr") * toMeters;
+    if (conf->hasProperty("curtainu"))
+      instrumentInfo.D_curtainu_value = conf->getDouble("curtainu") * toMeters;
+    if (conf->hasProperty("curtaind"))
+      instrumentInfo.D_curtaind_value = conf->getDouble("curtaind") * toMeters;
+  }
+
   return Geometry::Instrument_sptr();
 
   /*
@@ -699,8 +778,6 @@ void LoadBBY::loadEvents(API::Progress &prog, const char *progMsg,
                          EventProcessor &eventProcessor) {
   prog.doReport(progMsg);
 
-  bool countsInFrame = false;
-
   // select bin file
   int64_t fileSize = 0;
   const std::vector<std::string> &files = tarFile.files();
@@ -771,27 +848,19 @@ void LoadBBY::loadEvents(API::Progress &prog, const char *progMsg,
 
       if ((x == 0) && (y == 0) && (dt == 0xFFFFFFFF)) {
         tof = 0.0;
-
-        // only count frames that contain neutrons
-        if (countsInFrame) {
-          eventProcessor.endOfFrame();
-          countsInFrame = false;
-        }
+        eventProcessor.newFrame();
       } else if ((x >= HISTO_BINS_X) || (y >= HISTO_BINS_Y)) {
+        // ignore
       } else {
         // conversion from 100 nanoseconds to 1 microsecond
-        tof += (static_cast<int>(dt)) * 0.1;
+        tof += static_cast<int>(dt) * 0.1;
 
         eventProcessor.addEvent(x, y, tof);
-        countsInFrame = true;
       }
 
       progTracker.update(tarFile.selected_position());
     }
   }
-
-  if (countsInFrame)
-    eventProcessor.endOfFrame();
 }
 
 // DetectorBankFactory
diff --git a/Framework/DataHandling/src/PatchBBY.cpp b/Framework/DataHandling/src/PatchBBY.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1c70a8571420fd5dc7c27023c6ca845e57c7f81b
--- /dev/null
+++ b/Framework/DataHandling/src/PatchBBY.cpp
@@ -0,0 +1,275 @@
+#include "MantidAPI/FileProperty.h"
+#include "MantidDataHandling/PatchBBY.h"
+#include "MantidKernel/PropertyWithValue.h"
+
+#include <Poco/TemporaryFile.h>
+
+namespace Mantid {
+namespace DataHandling {
+
+// register the algorithm into the AlgorithmFactory
+DECLARE_ALGORITHM(PatchBBY)
+
+enum TYPE {
+  TYPE_INT,
+  TYPE_DBL,
+};
+
+struct PropertyInfo {
+  const char *const Group;
+  const char *const Name;
+  TYPE const Type;
+};
+
+// consts
+static char const *const HistoryStr = "History.log";
+static char const *const FilenameStr = "Filename";
+static PropertyInfo PatchableProperties[] = {
+    {"Group1", "Bm1Counts", TYPE_INT},
+    {"Group1", "AttPos", TYPE_DBL},
+
+    {"Group2", "MasterChopperFreq", TYPE_DBL},
+    {"Group2", "T0ChopperFreq", TYPE_DBL},
+    {"Group2", "T0ChopperPhase", TYPE_DBL},
+
+    //{ "Group3", "L1", TYPE_DBL},
+    {"Group3", "L2Det", TYPE_DBL},
+    {"Group3", "LTofDet", TYPE_DBL},
+
+    {"Group4", "L2CurtainL", TYPE_DBL},
+    {"Group4", "L2CurtainR", TYPE_DBL},
+    {"Group4", "L2CurtainU", TYPE_DBL},
+    {"Group4", "L2CurtainD", TYPE_DBL},
+
+    {"Group5", "CurtainL", TYPE_DBL},
+    {"Group5", "CurtainR", TYPE_DBL},
+    {"Group5", "CurtainU", TYPE_DBL},
+    {"Group5", "CurtainD", TYPE_DBL},
+};
+
+// load nx dataset
+template <class T>
+bool loadNXDataSet(NeXus::NXEntry &entry, const std::string &path, T &value) {
+  try {
+    NeXus::NXDataSetTyped<T> dataSet = entry.openNXDataSet<T>(path);
+    dataSet.load();
+
+    value = *dataSet();
+    return true;
+  } catch (std::runtime_error &) {
+    return false;
+  }
+}
+
+/**
+ * Initialise the algorithm. Declare properties which can be set before
+ * execution (input) or
+ * read from after the execution (output).
+ */
+void PatchBBY::init() {
+  // Specify file extensions which can be associated with a specific file.
+  std::vector<std::string> exts;
+
+  // Declare the Filename algorithm property. Mandatory. Sets the path to the
+  // file to load.
+  exts.clear();
+  exts.push_back(".tar");
+  declareProperty(
+      new API::FileProperty(FilenameStr, "", API::FileProperty::Load, exts),
+      "The filename of the stored data to be patched");
+
+  // patchable properties
+  for (auto itr = std::begin(PatchableProperties);
+       itr != std::end(PatchableProperties); ++itr) {
+    switch (itr->Type) {
+    case TYPE_INT:
+      declareProperty(new Kernel::PropertyWithValue<int>(
+                          itr->Name, EMPTY_INT(), Kernel::Direction::Input),
+                      "Optional");
+      break;
+
+    case TYPE_DBL:
+      declareProperty(new Kernel::PropertyWithValue<double>(
+                          itr->Name, EMPTY_DBL(), Kernel::Direction::Input),
+                      "Optional");
+      break;
+    }
+
+    setPropertyGroup(itr->Name, itr->Group);
+  }
+
+  declareProperty(new Kernel::PropertyWithValue<bool>("Reset", false,
+                                                      Kernel::Direction::Input),
+                  "Optional");
+}
+/**
+ * Execute the algorithm.
+ */
+void PatchBBY::exec() {
+  // get the name of the data file
+  std::string filename = getPropertyValue(FilenameStr);
+  ANSTO::Tar::File tarFile(filename);
+  if (!tarFile.good())
+    throw std::invalid_argument("invalid BBY file");
+
+  size_t hdfFiles = 0;
+  size_t binFiles = 0;
+  size_t logFiles = 0;
+  size_t logSize = 0;
+
+  // open file (and select hisotry file if it exists)
+  const std::vector<std::string> &files = tarFile.files();
+  for (auto itr = files.begin(); itr != files.end(); ++itr) {
+    auto len = itr->length();
+
+    if ((len > 4) && (itr->find_first_of("\\/", 0, 2) == std::string::npos)) {
+      if ((itr->compare(0, 3, "BBY") == 0) && (itr->rfind(".hdf") == len - 4))
+        hdfFiles++;
+      else if (itr->rfind(".bin") == len - 4)
+        binFiles++;
+      else if (itr->compare(HistoryStr) == 0) {
+        if (std::distance(itr, files.end()) != 1)
+          throw std::invalid_argument(
+              "invalid BBY file (history has to be at the end)");
+
+        logFiles++;
+        tarFile.select(itr->c_str());
+        logSize = tarFile.selected_size();
+      }
+    }
+  }
+
+  // check if it's valid
+  if ((hdfFiles != 1) || (binFiles != 1) || (logFiles > 1))
+    throw std::invalid_argument("invalid BBY file");
+
+  // read existing history
+  std::string logContent;
+  if (logFiles != 0) {
+    logContent.resize(logSize);
+    tarFile.read(&logContent[0], logSize);
+  }
+
+  // create new content
+  std::ostringstream logContentNewBuffer;
+  int tmp_int;
+  double tmp_dbl;
+  for (auto itr = std::begin(PatchableProperties);
+       itr != std::end(PatchableProperties); ++itr) {
+    auto property_value = getProperty(itr->Name);
+    // if (!isEmpty(property_value))
+    switch (itr->Type) {
+    case TYPE_INT:
+      tmp_int = property_value;
+      if (tmp_int != EMPTY_INT()) // !!!
+        logContentNewBuffer << itr->Name << " = " << tmp_int << std::endl;
+      break;
+
+    case TYPE_DBL:
+      tmp_dbl = property_value;
+      if (tmp_dbl != EMPTY_DBL()) // !!!
+        logContentNewBuffer << itr->Name << " = " << tmp_dbl << std::endl;
+      break;
+    }
+  }
+
+  // load original values from hdf
+  bool reset = getProperty("Reset");
+  if (reset) {
+    int64_t fileSize = 0;
+    for (auto itr = files.begin(); itr != files.end(); ++itr)
+      if (itr->rfind(".hdf") == itr->length() - 4) {
+        tarFile.select(itr->c_str());
+        fileSize = tarFile.selected_size();
+        break;
+      }
+
+    if (fileSize != 0) {
+      // extract hdf file into tmp file
+      Poco::TemporaryFile hdfFile;
+      boost::shared_ptr<FILE> handle(fopen(hdfFile.path().c_str(), "wb"),
+                                     fclose);
+      if (handle) {
+        // copy content
+        char buffer[4096];
+        size_t bytesRead;
+        while (0 != (bytesRead = tarFile.read(buffer, sizeof(buffer))))
+          fwrite(buffer, bytesRead, 1, handle.get());
+        handle.reset();
+
+        NeXus::NXRoot root(hdfFile.path());
+        NeXus::NXEntry entry = root.openFirstEntry();
+
+        float tmp_float;
+        int32_t tmp_int32 = 0;
+
+        if (loadNXDataSet(entry, "monitor/bm1_counts", tmp_int32))
+          logContentNewBuffer << "bm1_counts"
+                              << " = " << tmp_int32 << std::endl;
+        if (loadNXDataSet(entry, "instrument/att_pos", tmp_float))
+          logContentNewBuffer << "att_pos"
+                              << " = " << tmp_float << std::endl;
+
+        if (loadNXDataSet(entry, "instrument/master_chopper_freq", tmp_float))
+          logContentNewBuffer << "master_chopper_freq"
+                              << " = " << tmp_float << std::endl;
+        if (loadNXDataSet(entry, "instrument/t0_chopper_freq", tmp_float))
+          logContentNewBuffer << "t0_chopper_freq"
+                              << " = " << tmp_float << std::endl;
+        if (loadNXDataSet(entry, "instrument/t0_chopper_phase", tmp_float))
+          logContentNewBuffer << "t0_chopper_phase"
+                              << " = " << (tmp_float < 999.0 ? tmp_float : 0.0)
+                              << std::endl;
+
+        if (loadNXDataSet(entry, "instrument/L2_det", tmp_float))
+          logContentNewBuffer << "L2_det"
+                              << " = " << tmp_float << std::endl;
+        if (loadNXDataSet(entry, "instrument/Ltof_det", tmp_float))
+          logContentNewBuffer << "Ltof_det"
+                              << " = " << tmp_float << std::endl;
+
+        if (loadNXDataSet(entry, "instrument/L2_curtainl", tmp_float))
+          logContentNewBuffer << "L2_curtainl"
+                              << " = " << tmp_float << std::endl;
+        if (loadNXDataSet(entry, "instrument/L2_curtainr", tmp_float))
+          logContentNewBuffer << "L2_curtainr"
+                              << " = " << tmp_float << std::endl;
+        if (loadNXDataSet(entry, "instrument/L2_curtainu", tmp_float))
+          logContentNewBuffer << "L2_curtainu"
+                              << " = " << tmp_float << std::endl;
+        if (loadNXDataSet(entry, "instrument/L2_curtaind", tmp_float))
+          logContentNewBuffer << "L2_curtaind"
+                              << " = " << tmp_float << std::endl;
+
+        if (loadNXDataSet(entry, "instrument/detector/curtainl", tmp_float))
+          logContentNewBuffer << "curtainl"
+                              << " = " << tmp_float << std::endl;
+        if (loadNXDataSet(entry, "instrument/detector/curtainr", tmp_float))
+          logContentNewBuffer << "curtainr"
+                              << " = " << tmp_float << std::endl;
+        if (loadNXDataSet(entry, "instrument/detector/curtainu", tmp_float))
+          logContentNewBuffer << "curtainu"
+                              << " = " << tmp_float << std::endl;
+        if (loadNXDataSet(entry, "instrument/detector/curtaind", tmp_float))
+          logContentNewBuffer << "curtaind"
+                              << " = " << tmp_float << std::endl;
+      }
+    }
+  }
+
+  std::string logContentNew = logContentNewBuffer.str();
+  if (logContentNew.size() == 0)
+    throw std::invalid_argument("nothing to patch");
+
+  // merge log content
+  logContent.append(logContentNew);
+
+  // append patches to file
+  tarFile.close();
+  if (!ANSTO::Tar::File::append(filename, HistoryStr, logContent.c_str(),
+                                logContent.size()))
+    throw std::runtime_error("unable to patch");
+}
+
+} // DataHandling
+} // Mantid