Repository: NREL/OpenStudio (language: python)

Issue:
E+ 23.1.0: Wrap OutputControl:Timestamp
Enhancement Request
--------------
<!--- Provide a general summary of the feature you would like to see implemented -->

## Detailed Description
<!--- Provide a detailed description of the change or addition you are proposing. Include screenshot/schemas as appropriate -->

## Possible Implementation
Should be just like `OutputControl:Files`, but less fields: https://github.com/NREL/OpenStudio/pull/4059



Discussion / hints:

Fix patch:
diff --git a/resources/energyplus/ProposedEnergy+.idd b/resources/energyplus/ProposedEnergy+.idd
index b3fc2b54416..9cb604604e1 100644
--- a/resources/energyplus/ProposedEnergy+.idd
+++ b/resources/energyplus/ProposedEnergy+.idd
@@ -61857,6 +61857,22 @@ OutputControl:Files,
        \key No
        \default Yes
 
+OutputControl:Timestamp,
+       \memo Control timestamp format, currently applies only to JSON and native CSV (not CSV via ReadVars)
+       \unique-object
+  A1,  \field ISO 8601 Format
+       \note Use the ISO 8601 format YYYY-MM-DDThh:mm:ss
+       \type choice
+       \key Yes
+       \key No
+       \default No
+  A2;  \field Timestamp at Beginning of Interval
+       \note Determines where the timestamp is produced, either at the beginning (Yes) or end (No) of the interval
+       \type choice
+       \key Yes
+       \key No
+       \default No
+
 Output:JSON,
        \memo Output from EnergyPlus can be written to JSON format files.
        \unique-object
diff --git a/resources/model/OpenStudio.idd b/resources/model/OpenStudio.idd
index d91c19dfadc..de24d567079 100644
--- a/resources/model/OpenStudio.idd
+++ b/resources/model/OpenStudio.idd
@@ -35689,6 +35689,25 @@ OS:OutputControl:Files,
        \key No
        \required-field
 
+OS:OutputControl:Timestamp,
+       \memo Control timestamp format, currently applies only to JSON and native CSV (not CSV via ReadVars)
+       \unique-object
+  A1,  \field Handle
+       \type handle
+       \required-field
+  A2,  \field ISO 8601 Format
+       \note Use the ISO 8601 format YYYY-MM-DDThh:mm:ss
+       \type choice
+       \key Yes
+       \key No
+       \required-field
+  A3;  \field Timestamp at Beginning of Interval
+       \note Determines where the timestamp is produced, either at the beginning (Yes) or end (No) of the interval
+       \type choice
+       \key Yes
+       \key No
+       \required-field
+
 OS:OutputControl:ReportingTolerances,
        \memo Calculations of the time that setpoints are not met use a tolerance of 0.2C.
        \memo This object allows changing the tolerance used to determine when setpoints are being met.
diff --git a/src/energyplus/CMakeLists.txt b/src/energyplus/CMakeLists.txt
index 986c2f95cad..4be3e81fa4d 100644
--- a/src/energyplus/CMakeLists.txt
+++ b/src/energyplus/CMakeLists.txt
@@ -255,6 +255,7 @@ set(${target_name}_src
   ForwardTranslator/ForwardTranslateOutputControlFiles.cpp
   ForwardTranslator/ForwardTranslateOutputControlReportingTolerances.cpp
   ForwardTranslator/ForwardTranslateOutputControlTableStyle.cpp
+  ForwardTranslator/ForwardTranslateOutputControlTimestamp.cpp
   ForwardTranslator/ForwardTranslateOutputMeter.cpp
   ForwardTranslator/ForwardTranslateOutputVariable.cpp
   ForwardTranslator/ForwardTranslateOutputDebuggingData.cpp
@@ -545,6 +546,7 @@ set(${target_name}_src
   ReverseTranslator/ReverseTranslateOutputControlFiles.cpp
   ReverseTranslator/ReverseTranslateOutputControlReportingTolerances.cpp
   ReverseTranslator/ReverseTranslateOutputControlTableStyle.cpp
+  ReverseTranslator/ReverseTranslateOutputControlTimestamp.cpp
   ReverseTranslator/ReverseTranslateOutputDebuggingData.cpp
   ReverseTranslator/ReverseTranslateOutputDiagnostics.cpp
   ReverseTranslator/ReverseTranslateOutputEnergyManagementSystem.cpp
@@ -745,6 +747,7 @@ set(${target_name}_test_src
   Test/OutputControlFiles_GTest.cpp
   Test/OutputControlReportingTolerances_GTest.cpp
   Test/OutputControlTableStyle_GTest.cpp
+  Test/OutputControlTimestamp_GTest.cpp
   Test/OutputDebuggingData_GTest.cpp
   Test/OutputDiagnostics_GTest.cpp
   Test/OutputJSON_GTest.cpp
diff --git a/src/energyplus/ForwardTranslator.cpp b/src/energyplus/ForwardTranslator.cpp
index 7ea159033da..6b966ee2d7c 100644
--- a/src/energyplus/ForwardTranslator.cpp
+++ b/src/energyplus/ForwardTranslator.cpp
@@ -2292,6 +2292,11 @@ namespace energyplus {
         retVal = translateOutputControlTableStyle(outputControlTableStyle);
         break;
       }
+      case openstudio::IddObjectType::OS_OutputControl_Timestamp: {
+        auto outputControlTimestamp = modelObject.cast<OutputControlTimestamp>();
+        retVal = translateOutputControlTimestamp(outputControlTimestamp);
+        break;
+      }
       case openstudio::IddObjectType::OS_Output_DebuggingData: {
         auto mo = modelObject.cast<OutputDebuggingData>();
         retVal = translateOutputDebuggingData(mo);
@@ -3334,6 +3339,7 @@ namespace energyplus {
       IddObjectType::OS_OutputControl_Files,
       IddObjectType::OS_OutputControl_ReportingTolerances,
       IddObjectType::OS_OutputControl_Table_Style,
+      IddObjectType::OS_OutputControl_Timestamp,
       IddObjectType::OS_Output_Constructions,
       IddObjectType::OS_Output_DebuggingData,
       IddObjectType::OS_Output_Diagnostics,
diff --git a/src/energyplus/ForwardTranslator.hpp b/src/energyplus/ForwardTranslator.hpp
index 4f6c0087c7e..1f45a629679 100644
--- a/src/energyplus/ForwardTranslator.hpp
+++ b/src/energyplus/ForwardTranslator.hpp
@@ -315,6 +315,7 @@ namespace model {
   class OutputControlFiles;
   class OutputControlReportingTolerances;
   class OutputControlTableStyle;
+  class OutputControlTimestamp;
   class OutputDebuggingData;
   class OutputDiagnostics;
   class OutputJSON;
@@ -1172,6 +1173,8 @@ namespace energyplus {
 
     boost::optional<IdfObject> translateOutputControlTableStyle(model::OutputControlTableStyle& modelObject);
 
+    boost::optional<IdfObject> translateOutputControlTimestamp(model::OutputControlTimestamp& modelObject);
+
     boost::optional<IdfObject> translateOutputDebuggingData(model::OutputDebuggingData& modelObject);
 
     boost::optional<IdfObject> translateOutputDiagnostics(model::OutputDiagnostics& modelObject);
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateOutputControlTimestamp.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateOutputControlTimestamp.cpp
new file mode 100644
index 00000000000..07a606a8b3d
--- /dev/null
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateOutputControlTimestamp.cpp
@@ -0,0 +1,67 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include "../ForwardTranslator.hpp"
+#include "../../model/Model.hpp"
+
+#include "../../model/OutputControlTimestamp.hpp"
+
+#include <utilities/idd/OutputControl_Timestamp_FieldEnums.hxx>
+// #include "../../utilities/idd/IddEnums.hpp"
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::model;
+
+namespace openstudio {
+
+namespace energyplus {
+
+  boost::optional<IdfObject> ForwardTranslator::translateOutputControlTimestamp(model::OutputControlTimestamp& modelObject) {
+
+    IdfObject idfObject = createRegisterAndNameIdfObject(openstudio::IddObjectType::OutputControl_Timestamp, modelObject);
+
+    // ISO 8601 Format: Optional Boolean
+    if (modelObject.iso8601Format()) {
+      idfObject.setString(OutputControl_TimestampFields::ISO8601Format, "Yes");
+    } else {
+      idfObject.setString(OutputControl_TimestampFields::ISO8601Format, "No");
+    }
+
+    // Timestamp at Beginning of Interval: Optional Boolean
+    if (modelObject.timestampAtBeginningOfInterval()) {
+      idfObject.setString(OutputControl_TimestampFields::TimestampatBeginningofInterval, "Yes");
+    } else {
+      idfObject.setString(OutputControl_TimestampFields::TimestampatBeginningofInterval, "No");
+    }
+
+    return idfObject;
+  }  // End of translate function
+
+}  // end namespace energyplus
+}  // end namespace openstudio
\ No newline at end of file
diff --git a/src/energyplus/ReverseTranslator.cpp b/src/energyplus/ReverseTranslator.cpp
index bac566dddc7..27d10cd38ff 100644
--- a/src/energyplus/ReverseTranslator.cpp
+++ b/src/energyplus/ReverseTranslator.cpp
@@ -744,6 +744,10 @@ namespace energyplus {
         modelObject = translateOutputControlTableStyle(workspaceObject);
         break;
       }
+      case openstudio::IddObjectType::OutputControl_Timestamp: {
+        modelObject = translateOutputControlTimestamp(workspaceObject);
+        break;
+      }
       case openstudio::IddObjectType::Output_Schedules: {
         modelObject = translateOutputSchedules(workspaceObject);
         break;
diff --git a/src/energyplus/ReverseTranslator.hpp b/src/energyplus/ReverseTranslator.hpp
index 822ae96d184..406f3917bd8 100644
--- a/src/energyplus/ReverseTranslator.hpp
+++ b/src/energyplus/ReverseTranslator.hpp
@@ -251,6 +251,8 @@ namespace energyplus {
 
     boost::optional<model::ModelObject> translateOutputControlTableStyle(const WorkspaceObject& workspaceObject);
 
+    boost::optional<model::ModelObject> translateOutputControlTimestamp(const WorkspaceObject& workspaceObject);
+
     boost::optional<model::ModelObject> translateOutputDebuggingData(const WorkspaceObject& workspaceObject);
 
     boost::optional<model::ModelObject> translateOutputDiagnostics(const WorkspaceObject& workspaceObject);
diff --git a/src/energyplus/ReverseTranslator/ReverseTranslateOutputControlTimestamp.cpp b/src/energyplus/ReverseTranslator/ReverseTranslateOutputControlTimestamp.cpp
new file mode 100644
index 00000000000..41c982be101
--- /dev/null
+++ b/src/energyplus/ReverseTranslator/ReverseTranslateOutputControlTimestamp.cpp
@@ -0,0 +1,73 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include "../ReverseTranslator.hpp"
+
+#include "../../model/OutputControlTimestamp.hpp"
+#include "../../model/OutputControlTimestamp_Impl.hpp"
+
+#include <utilities/idd/OutputControl_Timestamp_FieldEnums.hxx>
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::model;
+
+namespace openstudio {
+
+namespace energyplus {
+
+  boost::optional<ModelObject> ReverseTranslator::translateOutputControlTimestamp(const WorkspaceObject& workspaceObject) {
+    boost::optional<ModelObject> result;
+
+    // This is a Unique ModelObject
+    openstudio::model::OutputControlTimestamp modelObject = m_model.getUniqueModelObject<OutputControlTimestamp>();
+
+    if (boost::optional<std::string> _iso8601Format = workspaceObject.getString(OutputControl_TimestampFields::ISO8601Format, true)) {
+      if (istringEqual("Yes", _iso8601Format.get())) {
+        modelObject.setISO8601Format(true);
+      } else {
+        modelObject.setISO8601Format(false);
+      }
+    }
+
+    if (boost::optional<std::string> _timestampAtBeginningofInterval =
+          workspaceObject.getString(OutputControl_TimestampFields::TimestampatBeginningofInterval, true)) {
+      if (istringEqual("Yes", _timestampAtBeginningofInterval.get())) {
+        modelObject.setTimestampAtBeginningOfInterval(true);
+      } else {
+        modelObject.setTimestampAtBeginningOfInterval(false);
+      }
+    }
+
+    result = modelObject;
+    return result;
+
+  }  // End of translate function
+
+}  // end namespace energyplus
+}  // end namespace openstudio
diff --git a/src/energyplus/Test/OutputControlTimestamp_GTest.cpp b/src/energyplus/Test/OutputControlTimestamp_GTest.cpp
new file mode 100644
index 00000000000..7bfeaf7b6f7
--- /dev/null
+++ b/src/energyplus/Test/OutputControlTimestamp_GTest.cpp
@@ -0,0 +1,111 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include <gtest/gtest.h>
+#include "EnergyPlusFixture.hpp"
+
+#include "../ForwardTranslator.hpp"
+#include "../ReverseTranslator.hpp"
+
+#include "../../model/Model.hpp"
+#include "../../model/OutputControlTimestamp.hpp"
+#include "../../model/OutputControlTimestamp_Impl.hpp"
+
+#include "../../utilities/idf/IdfFile.hpp"
+#include "../../utilities/idf/Workspace.hpp"
+#include "../../utilities/idf/IdfObject.hpp"
+#include "../../utilities/idf/WorkspaceObject.hpp"
+
+#include <utilities/idd/OutputControl_Timestamp_FieldEnums.hxx>
+#include <utilities/idd/IddEnums.hxx>
+
+using namespace openstudio::energyplus;
+using namespace openstudio::model;
+using namespace openstudio;
+
+TEST_F(EnergyPlusFixture, ForwardTranslator_OutputControlTimestamp) {
+
+  ForwardTranslator ft;
+
+  // Create a model
+  Model m;
+
+  // Get the unique object
+  OutputControlTimestamp outputControlTimestamp = m.getUniqueModelObject<OutputControlTimestamp>();
+
+  // Check all cases where a single output request is True so we know we assigned the fields correctly
+  auto boolToString = [](bool b) { return b ? "Yes" : "No"; };
+
+  for (size_t i = 0; i < 2; ++i) {
+    bool status[2] = {false};
+    status[i] = true;
+    EXPECT_TRUE(outputControlTimestamp.setISO8601Format(status[0]));
+    EXPECT_TRUE(outputControlTimestamp.setTimestampAtBeginningOfInterval(status[1]));
+
+    Workspace w = ft.translateModel(m);
+    WorkspaceObjectVector idfObjs = w.getObjectsByType(IddObjectType::OutputControl_Timestamp);
+    ASSERT_EQ(1u, idfObjs.size());
+
+    WorkspaceObject idf_outputControlTimestamp(idfObjs[0]);
+
+    EXPECT_EQ(boolToString(status[0]), idf_outputControlTimestamp.getString(OutputControl_TimestampFields::ISO8601Format).get());
+    EXPECT_EQ(boolToString(status[1]), idf_outputControlTimestamp.getString(OutputControl_TimestampFields::TimestampatBeginningofInterval).get());
+  }
+}
+
+TEST_F(EnergyPlusFixture, ReverseTranslator_OutputControlTimestamp) {
+
+  ReverseTranslator rt;
+
+  Workspace w(StrictnessLevel::Minimal, IddFileType::EnergyPlus);
+
+  // Not there, Model shouldn't have it either
+  Model m = rt.translateWorkspace(w);
+  EXPECT_FALSE(m.getOptionalUniqueModelObject<OutputControlTimestamp>());
+
+  OptionalWorkspaceObject _i_outputControlTimestamp = w.addObject(IdfObject(IddObjectType::OutputControl_Timestamp));
+  ASSERT_TRUE(_i_outputControlTimestamp);
+
+  auto boolToString = [](bool b) { return b ? "Yes" : "No"; };
+
+  for (size_t i = 0; i < 2; ++i) {
+    bool status[2] = {false};
+    status[i] = true;
+    EXPECT_TRUE(_i_outputControlTimestamp->setString(OutputControl_TimestampFields::ISO8601Format, boolToString(status[0])));
+    EXPECT_TRUE(_i_outputControlTimestamp->setString(OutputControl_TimestampFields::TimestampatBeginningofInterval, boolToString(status[1])));
+
+    Model m = rt.translateWorkspace(w);
+
+    // // Get the unique object
+    OutputControlTimestamp outputControlTimestamp = m.getUniqueModelObject<OutputControlTimestamp>();
+
+    EXPECT_EQ(status[0], outputControlTimestamp.iso8601Format());
+    EXPECT_EQ(status[1], outputControlTimestamp.timestampAtBeginningOfInterval());
+  }
+}
diff --git a/src/model/CMakeLists.txt b/src/model/CMakeLists.txt
index ea16d159bf9..825eaaca3b7 100644
--- a/src/model/CMakeLists.txt
+++ b/src/model/CMakeLists.txt
@@ -1063,6 +1063,9 @@ set(${target_name}_src
   OutputControlTableStyle.hpp
   OutputControlTableStyle_Impl.hpp
   OutputControlTableStyle.cpp
+  OutputControlTimestamp.hpp
+  OutputControlTimestamp_Impl.hpp
+  OutputControlTimestamp.cpp
   OutputDebuggingData.hpp
   OutputDebuggingData_Impl.hpp
   OutputDebuggingData.cpp
@@ -2158,6 +2161,7 @@ set(${target_name}_test_src
   test/OutputControlFiles_GTest.cpp
   test/OutputControlReportingTolerances_GTest.cpp
   test/OutputControlTableStyle_GTest.cpp
+  test/OutputControlTimestamp_GTest.cpp
   test/OutputDebuggingData_GTest.cpp
   test/OutputJSON_GTest.cpp
   test/OutputSQLite_GTest.cpp
diff --git a/src/model/ConcreteModelObjects.hpp b/src/model/ConcreteModelObjects.hpp
index 1d362b0de3e..9d7cdb4d8e9 100644
--- a/src/model/ConcreteModelObjects.hpp
+++ b/src/model/ConcreteModelObjects.hpp
@@ -350,6 +350,7 @@
 #include "OutputControlFiles.hpp"
 #include "OutputControlReportingTolerances.hpp"
 #include "OutputControlTableStyle.hpp"
+#include "OutputControlTimestamp.hpp"
 #include "OutputDebuggingData.hpp"
 #include "OutputDiagnostics.hpp"
 #include "OutputEnergyManagementSystem.hpp"
@@ -896,6 +897,7 @@
 #include "OutputControlFiles_Impl.hpp"
 #include "OutputControlReportingTolerances_Impl.hpp"
 #include "OutputControlTableStyle_Impl.hpp"
+#include "OutputControlTimestamp_Impl.hpp"
 #include "OutputDebuggingData_Impl.hpp"
 #include "OutputDiagnostics_Impl.hpp"
 #include "OutputEnergyManagementSystem_Impl.hpp"
diff --git a/src/model/Model.cpp b/src/model/Model.cpp
index 097e802b45c..0dd01812e41 100644
--- a/src/model/Model.cpp
+++ b/src/model/Model.cpp
@@ -301,6 +301,22 @@ namespace model {
       return m_cachedOutputControlTableStyle;
     }
 
+    boost::optional<OutputControlTimestamp> Model_Impl::outputControlTimestamp() const {
+      if (m_cachedOutputControlTimestamp) {
+        return m_cachedOutputControlTimestamp;
+      }
+
+      boost::optional<OutputControlTimestamp> result = this->model().getOptionalUniqueModelObject<OutputControlTimestamp>();
+      if (result) {
+        m_cachedOutputControlTimestamp = result;
+        result->getImpl<OutputControlTimestamp_Impl>()
+          ->OutputControlTimestamp_Impl::onRemoveFromWorkspace.connect<Model_Impl, &Model_Impl::clearCachedOutputControlTimestamp>(
+            const_cast<openstudio::model::detail::Model_Impl*>(this));
+      }
+
+      return m_cachedOutputControlTimestamp;
+    }
+
     boost::optional<OutputDiagnostics> Model_Impl::outputDiagnostics() const {
       if (m_cachedOutputDiagnostics) {
         return m_cachedOutputDiagnostics;
@@ -1508,6 +1524,7 @@ namespace model {
       clearCachedOutputControlFiles(dummy);
       clearCachedOutputControlReportingTolerances(dummy);
       clearCachedOutputControlTableStyle(dummy);
+      clearCachedOutputControlTimestamp(dummy);
       clearCachedOutputDiagnostics(dummy);
       clearCachedOutputDebuggingData(dummy);
       clearCachedOutputJSON(dummy);
@@ -1570,6 +1587,10 @@ namespace model {
       m_cachedOutputControlTableStyle.reset();
     }
 
+    void Model_Impl::clearCachedOutputControlTimestamp(const Handle&) {
+      m_cachedOutputControlTimestamp.reset();
+    }
+
     void Model_Impl::clearCachedOutputDiagnostics(const Handle&) {
       m_cachedOutputDiagnostics.reset();
     }
@@ -1901,6 +1922,10 @@ namespace model {
     return getImpl<detail::Model_Impl>()->outputControlTableStyle();
   }
 
+  boost::optional<OutputControlTimestamp> Model::outputControlTimestamp() const {
+    return getImpl<detail::Model_Impl>()->outputControlTimestamp();
+  }
+
   boost::optional<OutputDiagnostics> Model::outputDiagnostics() const {
     return getImpl<detail::Model_Impl>()->outputDiagnostics();
   }
@@ -3436,6 +3461,15 @@ namespace model {
     }
   }
 
+  template <>
+  OutputControlTimestamp Model::getUniqueModelObject<OutputControlTimestamp>() {
+    if (boost::optional<OutputControlTimestamp> _b = outputControlTimestamp()) {
+      return _b.get();
+    } else {
+      return OutputControlTimestamp(*this);
+    }
+  }
+
   template <>
   OutputDiagnostics Model::getUniqueModelObject<OutputDiagnostics>() {
     if (boost::optional<OutputDiagnostics> _b = outputDiagnostics()) {
@@ -4143,6 +4177,7 @@ namespace model {
     REGISTER_CONSTRUCTOR(OutputControlFiles);
     REGISTER_CONSTRUCTOR(OutputControlReportingTolerances);
     REGISTER_CONSTRUCTOR(OutputControlTableStyle);
+    REGISTER_CONSTRUCTOR(OutputControlTimestamp);
     REGISTER_CONSTRUCTOR(OutputDebuggingData);
     REGISTER_CONSTRUCTOR(OutputDiagnostics);
     REGISTER_CONSTRUCTOR(OutputEnergyManagementSystem);
@@ -4709,6 +4744,7 @@ namespace model {
     REGISTER_COPYCONSTRUCTORS(OutputControlFiles);
     REGISTER_COPYCONSTRUCTORS(OutputControlReportingTolerances);
     REGISTER_COPYCONSTRUCTORS(OutputControlTableStyle);
+    REGISTER_COPYCONSTRUCTORS(OutputControlTimestamp);
     REGISTER_COPYCONSTRUCTORS(OutputDebuggingData);
     REGISTER_COPYCONSTRUCTORS(OutputDiagnostics);
     REGISTER_COPYCONSTRUCTORS(OutputEnergyManagementSystem);
diff --git a/src/model/Model.hpp b/src/model/Model.hpp
index 405784004d2..e8e91164f07 100644
--- a/src/model/Model.hpp
+++ b/src/model/Model.hpp
@@ -54,6 +54,7 @@ namespace model {
   class OutputControlFiles;
   class OutputControlReportingTolerances;
   class OutputControlTableStyle;
+  class OutputControlTimestamp;
   class OutputDiagnostics;
   class OutputDebuggingData;
   class OutputJSON;
@@ -175,6 +176,10 @@ namespace model {
    *  object which can be significantly faster than calling getOptionalUniqueModelObject<OutputControlTableStyle>(). */
     boost::optional<OutputControlTableStyle> outputControlTableStyle() const;
 
+    /** Get the OutputControlTimestamp object if there is one, this implementation uses a cached reference to the OutputControlTimestamp
+   *  object which can be significantly faster than calling getOptionalUniqueModelObject<OutputControlTimestamp>(). */
+    boost::optional<OutputControlTimestamp> outputControlTimestamp() const;
+
     /** Get the OutputDiagnostics object if there is one, this implementation uses a cached reference to the OutputDiagnostics
    *  object which can be significantly faster than calling getOptionalUniqueModelObject<OutputDiagnostics>(). */
     boost::optional<OutputDiagnostics> outputDiagnostics() const;
@@ -725,6 +730,9 @@ namespace model {
   template <>
   MODEL_API OutputControlTableStyle Model::getUniqueModelObject<OutputControlTableStyle>();
 
+  template <>
+  MODEL_API OutputControlTimestamp Model::getUniqueModelObject<OutputControlTimestamp>();
+
   template <>
   MODEL_API OutputDiagnostics Model::getUniqueModelObject<OutputDiagnostics>();
 
diff --git a/src/model/ModelSimulation.i b/src/model/ModelSimulation.i
index e27a0d46028..ac25115699c 100644
--- a/src/model/ModelSimulation.i
+++ b/src/model/ModelSimulation.i
@@ -75,6 +75,7 @@ UNIQUEMODELOBJECT_TEMPLATES(InsideSurfaceConvectionAlgorithm);
 UNIQUEMODELOBJECT_TEMPLATES(OutputControlFiles);
 UNIQUEMODELOBJECT_TEMPLATES(OutputControlReportingTolerances);
 UNIQUEMODELOBJECT_TEMPLATES(OutputControlTableStyle);
+UNIQUEMODELOBJECT_TEMPLATES(OutputControlTimestamp);
 UNIQUEMODELOBJECT_TEMPLATES(OutputDebuggingData);
 UNIQUEMODELOBJECT_TEMPLATES(OutputDiagnostics);
 UNIQUEMODELOBJECT_TEMPLATES(OutputJSON);
@@ -129,6 +130,7 @@ SWIG_UNIQUEMODELOBJECT(InsideSurfaceConvectionAlgorithm);
 SWIG_UNIQUEMODELOBJECT(OutputControlFiles);
 SWIG_UNIQUEMODELOBJECT(OutputControlReportingTolerances);
 SWIG_UNIQUEMODELOBJECT(OutputControlTableStyle);
+SWIG_UNIQUEMODELOBJECT(OutputControlTimestamp);
 SWIG_UNIQUEMODELOBJECT(OutputDebuggingData);
 SWIG_UNIQUEMODELOBJECT(OutputDiagnostics);
 SWIG_UNIQUEMODELOBJECT(OutputJSON);
@@ -214,6 +216,10 @@ SWIG_UNIQUEMODELOBJECT(PerformancePrecisionTradeoffs);
           return model.outputControlTableStyle();
         }
 
+        boost::optional<OutputControlTimestamp> outputControlTimestamp(const openstudio::model::Model& model) {
+          return model.outputControlTimestamp();
+        }
+
         boost::optional<OutputDebuggingData> outputDebuggingData(const openstudio::model::Model& model) {
           return model.outputDebuggingData();
         }
@@ -381,6 +387,10 @@ SWIG_UNIQUEMODELOBJECT(PerformancePrecisionTradeoffs);
         return OpenStudio.OpenStudioModelSimulation.outputControlTableStyle(this);
       }
 
+      public OptionalOutputControlTimestamp outputControlTimestamp() {
+        return OpenStudio.OpenStudioModelSimulation.outputControlTimestamp(this);
+      }
+
       public OptionalOutputDebuggingData outputDebuggingData() {
         return OpenStudio.OpenStudioModelSimulation.outputDebuggingData(this);
       }
diff --git a/src/model/Model_Impl.hpp b/src/model/Model_Impl.hpp
index e838562307e..6fdfbdc0237 100644
--- a/src/model/Model_Impl.hpp
+++ b/src/model/Model_Impl.hpp
@@ -36,6 +36,7 @@
 #include "OutputControlFiles.hpp"
 #include "OutputControlReportingTolerances.hpp"
 #include "OutputControlTableStyle.hpp"
+#include "OutputControlTimestamp.hpp"
 #include "OutputDiagnostics.hpp"
 #include "OutputDebuggingData.hpp"
 #include "OutputJSON.hpp"
@@ -194,6 +195,10 @@ namespace model {
      *  object which can be significantly faster than calling getOptionalUniqueModelObject<OutputControlTableStyle>(). */
       boost::optional<OutputControlTableStyle> outputControlTableStyle() const;
 
+      /** Get the OutputControlTimestamp object if there is one, this implementation uses a cached reference to the OutputControlTimestamp
+     *  object which can be significantly faster than calling getOptionalUniqueModelObject<OutputControlTimestamp>(). */
+      boost::optional<OutputControlTimestamp> outputControlTimestamp() const;
+
       /** Get the OutputDiagnostics object if there is one, this implementation uses a cached reference to the OutputDiagnostics
      *  object which can be significantly faster than calling getOptionalUniqueModelObject<OutputDiagnostics>(). */
       boost::optional<OutputDiagnostics> outputDiagnostics() const;
@@ -211,7 +216,7 @@ namespace model {
       boost::optional<OutputSQLite> outputSQLite() const;
 
       /** Get the OutputEnergyManagementSystem object if there is one, this implementation uses a cached reference to the OutputEnergyManagementSystem
-     *  object which can be significantly faster than calling getOptionalUniqueModelObject<OutputControlFiles>(). */
+     *  object which can be significantly faster than calling getOptionalUniqueModelObject<OutputEnergyManagementSystem>(). */
       boost::optional<OutputEnergyManagementSystem> outputEnergyManagementSystem() const;
 
       /** Get the OutputTableSummaryReports object if there is one, this implementation uses a cached reference to the OutputTableSummaryReports
@@ -485,6 +490,7 @@ namespace model {
       mutable boost::optional<OutputControlFiles> m_cachedOutputControlFiles;
       mutable boost::optional<OutputControlReportingTolerances> m_cachedOutputControlReportingTolerances;
       mutable boost::optional<OutputControlTableStyle> m_cachedOutputControlTableStyle;
+      mutable boost::optional<OutputControlTimestamp> m_cachedOutputControlTimestamp;
       mutable boost::optional<OutputDiagnostics> m_cachedOutputDiagnostics;
       mutable boost::optional<OutputDebuggingData> m_cachedOutputDebuggingData;
       mutable boost::optional<OutputJSON> m_cachedOutputJSON;
@@ -534,6 +540,7 @@ namespace model {
       void clearCachedOutputControlFiles(const Handle& handle);
       void clearCachedOutputControlReportingTolerances(const Handle& handle);
       void clearCachedOutputControlTableStyle(const Handle& handle);
+      void clearCachedOutputControlTimestamp(const Handle& handle);
       void clearCachedOutputDiagnostics(const Handle& handle);
       void clearCachedOutputDebuggingData(const Handle& handle);
       void clearCachedOutputJSON(const Handle& handle);
diff --git a/src/model/OutputControlTimestamp.cpp b/src/model/OutputControlTimestamp.cpp
new file mode 100644
index 00000000000..34349df93f2
--- /dev/null
+++ b/src/model/OutputControlTimestamp.cpp
@@ -0,0 +1,122 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include "OutputControlTimestamp.hpp"
+#include "OutputControlTimestamp_Impl.hpp"
+
+#include "Model.hpp"
+#include "Model_Impl.hpp"
+
+#include <utilities/idd/IddFactory.hxx>
+#include <utilities/idd/IddEnums.hxx>
+#include <utilities/idd/OS_OutputControl_Timestamp_FieldEnums.hxx>
+
+#include "../utilities/core/Assert.hpp"
+
+namespace openstudio {
+namespace model {
+
+  namespace detail {
+
+    OutputControlTimestamp_Impl::OutputControlTimestamp_Impl(const IdfObject& idfObject, Model_Impl* model, bool keepHandle)
+      : ModelObject_Impl(idfObject, model, keepHandle) {
+      OS_ASSERT(idfObject.iddObject().type() == OutputControlTimestamp::iddObjectType());
+    }
+
+    OutputControlTimestamp_Impl::OutputControlTimestamp_Impl(const openstudio::detail::WorkspaceObject_Impl& other, Model_Impl* model,
+                                                             bool keepHandle)
+      : ModelObject_Impl(other, model, keepHandle) {
+      OS_ASSERT(other.iddObject().type() == OutputControlTimestamp::iddObjectType());
+    }
+
+    OutputControlTimestamp_Impl::OutputControlTimestamp_Impl(const OutputControlTimestamp_Impl& other, Model_Impl* model, bool keepHandle)
+      : ModelObject_Impl(other, model, keepHandle) {}
+
+    const std::vector<std::string>& OutputControlTimestamp_Impl::outputVariableNames() const {
+      static std::vector<std::string> result;
+      if (result.empty()) {
+      }
+      return result;
+    }
+
+    IddObjectType OutputControlTimestamp_Impl::iddObjectType() const {
+      return OutputControlTimestamp::iddObjectType();
+    }
+
+    bool OutputControlTimestamp_Impl::iso8601Format() const {
+      return getBooleanFieldValue(OS_OutputControl_TimestampFields::ISO8601Format);
+    }
+
+    bool OutputControlTimestamp_Impl::timestampAtBeginningOfInterval() const {
+      return getBooleanFieldValue(OS_OutputControl_TimestampFields::TimestampatBeginningofInterval);
+    }
+
+    bool OutputControlTimestamp_Impl::setISO8601Format(bool iso8601Format) {
+      return setBooleanFieldValue(OS_OutputControl_TimestampFields::ISO8601Format, iso8601Format);
+    }
+
+    bool OutputControlTimestamp_Impl::setTimestampAtBeginningOfInterval(bool timestampAtBeginningOfInterval) {
+      return setBooleanFieldValue(OS_OutputControl_TimestampFields::TimestampatBeginningofInterval, timestampAtBeginningOfInterval);
+    }
+
+  }  // namespace detail
+
+  IddObjectType OutputControlTimestamp::iddObjectType() {
+    return IddObjectType(IddObjectType::OS_OutputControl_Timestamp);
+  }
+
+  bool OutputControlTimestamp::iso8601Format() const {
+    return getImpl<detail::OutputControlTimestamp_Impl>()->iso8601Format();
+  }
+
+  bool OutputControlTimestamp::timestampAtBeginningOfInterval() const {
+    return getImpl<detail::OutputControlTimestamp_Impl>()->timestampAtBeginningOfInterval();
+  }
+
+  bool OutputControlTimestamp::setISO8601Format(bool iso8601Format) {
+    return getImpl<detail::OutputControlTimestamp_Impl>()->setISO8601Format(iso8601Format);
+  }
+
+  bool OutputControlTimestamp::setTimestampAtBeginningOfInterval(bool timestampAtBeginningOfInterval) {
+    return getImpl<detail::OutputControlTimestamp_Impl>()->setTimestampAtBeginningOfInterval(timestampAtBeginningOfInterval);
+  }
+
+  /// @cond
+  OutputControlTimestamp::OutputControlTimestamp(std::shared_ptr<detail::OutputControlTimestamp_Impl> impl) : ModelObject(std::move(impl)) {}
+  OutputControlTimestamp::OutputControlTimestamp(Model& model) : ModelObject(OutputControlTimestamp::iddObjectType(), model) {
+    // This is a required-field, so pick one...
+    // Same defaults as EnergyPlus IDD
+    setISO8601Format(false);
+    setTimestampAtBeginningOfInterval(false);
+  }
+
+  /// @endcond
+
+}  // namespace model
+}  // namespace openstudio
diff --git a/src/model/OutputControlTimestamp.hpp b/src/model/OutputControlTimestamp.hpp
new file mode 100644
index 00000000000..847d5c10e64
--- /dev/null
+++ b/src/model/OutputControlTimestamp.hpp
@@ -0,0 +1,109 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#ifndef MODEL_OUTPUTCONTROLTIMESTAMP_HPP
+#define MODEL_OUTPUTCONTROLTIMESTAMP_HPP
+
+#include <model/ModelAPI.hpp>
+#include "ModelObject.hpp"
+
+namespace openstudio {
+namespace model {
+
+  namespace detail {
+
+    class OutputControlTimestamp_Impl;
+
+  }  // namespace detail
+
+  /** OutputControlTimestamp is a ModelObject that wraps the OpenStudio IDD object 'OS:OutputControl:Timestamp'. */
+  class MODEL_API OutputControlTimestamp : public ModelObject
+  {
+   public:
+    /** @name Constructors and Destructors */
+    //@{
+
+    virtual ~OutputControlTimestamp() = default;
+    // Default the copy and move operators because the virtual dtor is explicit
+    OutputControlTimestamp(const OutputControlTimestamp& other) = default;
+    OutputControlTimestamp(OutputControlTimestamp&& other) = default;
+    OutputControlTimestamp& operator=(const OutputControlTimestamp&) = default;
+    OutputControlTimestamp& operator=(OutputControlTimestamp&&) = default;
+
+    //@}
+
+    static IddObjectType iddObjectType();
+
+    /** @name Getters */
+    //@{
+
+    bool iso8601Format() const;
+
+    bool timestampAtBeginningOfInterval() const;
+
+    //@}
+    /** @name Setters */
+    //@{
+
+    bool setISO8601Format(bool iso8601Format);
+
+    bool setTimestampAtBeginningOfInterval(bool timestampAtBeginningOfInterval);
+
+    //@}
+    /** @name Other */
+    //@{
+
+    //@}
+   protected:
+    /// @cond
+    using ImplType = detail::OutputControlTimestamp_Impl;
+
+    explicit OutputControlTimestamp(std::shared_ptr<detail::OutputControlTimestamp_Impl> impl);
+
+    friend class detail::OutputControlTimestamp_Impl;
+    friend class Model;
+    friend class IdfObject;
+    friend class openstudio::detail::IdfObject_Impl;
+    explicit OutputControlTimestamp(Model& model);
+
+    /// @endcond
+   private:
+    REGISTER_LOGGER("openstudio.model.OutputControlTimestamp");
+  };
+
+  /** \relates OutputControlTimestamp*/
+  using OptionalOutputControlTimestamp = boost::optional<OutputControlTimestamp>;
+
+  /** \relates OutputControlTimestamp*/
+  using OutputControlTimestampVector = std::vector<OutputControlTimestamp>;
+
+}  // namespace model
+}  // namespace openstudio
+
+#endif  // MODEL_OUTPUTCONTROLTIMESTAMP_HPP
diff --git a/src/model/OutputControlTimestamp_Impl.hpp b/src/model/OutputControlTimestamp_Impl.hpp
new file mode 100644
index 00000000000..e8cedbd0401
--- /dev/null
+++ b/src/model/OutputControlTimestamp_Impl.hpp
@@ -0,0 +1,95 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#ifndef MODEL_OUTPUTCONTROLTIMESTAMP_IMPL_HPP
+#define MODEL_OUTPUTCONTROLTIMESTAMP_IMPL_HPP
+
+#include <model/ModelAPI.hpp>
+#include "ModelObject_Impl.hpp"
+
+namespace openstudio {
+namespace model {
+
+  namespace detail {
+
+    /** OutputControlTimestamp_Impl is a ModelObject_Impl that is the implementation class for OutputControlTimestamp.*/
+    class MODEL_API OutputControlTimestamp_Impl : public ModelObject_Impl
+    {
+     public:
+      /** @name Constructors and Destructors */
+      //@{
+
+      OutputControlTimestamp_Impl(const IdfObject& idfObject, Model_Impl* model, bool keepHandle);
+
+      OutputControlTimestamp_Impl(const openstudio::detail::WorkspaceObject_Impl& other, Model_Impl* model, bool keepHandle);
+
+      OutputControlTimestamp_Impl(const OutputControlTimestamp_Impl& other, Model_Impl* model, bool keepHandle);
+
+      virtual ~OutputControlTimestamp_Impl() = default;
+
+      //@}
+      /** @name Virtual Methods */
+      //@{
+
+      virtual const std::vector<std::string>& outputVariableNames() const override;
+
+      virtual IddObjectType iddObjectType() const override;
+
+      //@}
+      /** @name Getters */
+      //@{
+
+      bool iso8601Format() const;
+
+      bool timestampAtBeginningOfInterval() const;
+
+      //@}
+      /** @name Setters */
+      //@{
+
+      bool setISO8601Format(bool iso8601Format);
+
+      bool setTimestampAtBeginningOfInterval(bool timestampAtBeginningOfInterval);
+
+      //@}
+      /** @name Other */
+      //@{
+
+      //@}
+     protected:
+     private:
+      REGISTER_LOGGER("openstudio.model.OutputControlTimestamp");
+    };
+
+  }  // namespace detail
+
+}  // namespace model
+}  // namespace openstudio
+
+#endif  // MODEL_OUTPUTCONTROLTIMESTAMP_IMPL_HPP


Test patch:
diff --git a/src/model/test/OutputControlTimestamp_GTest.cpp b/src/model/test/OutputControlTimestamp_GTest.cpp
new file mode 100644
index 00000000000..bce57b09471
--- /dev/null
+++ b/src/model/test/OutputControlTimestamp_GTest.cpp
@@ -0,0 +1,53 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include "ModelFixture.hpp"
+
+#include "../OutputControlTimestamp.hpp"
+#include "../OutputControlTimestamp_Impl.hpp"
+
+using namespace openstudio;
+using namespace openstudio::model;
+
+TEST_F(ModelFixture, OutputControlTimestamp_GettersSetters) {
+  Model m;
+  OutputControlTimestamp outputControlTimestamp = m.getUniqueModelObject<OutputControlTimestamp>();
+
+  EXPECT_FALSE(outputControlTimestamp.iso8601Format());
+  EXPECT_TRUE(outputControlTimestamp.setISO8601Format(true));
+  EXPECT_TRUE(outputControlTimestamp.iso8601Format());
+  EXPECT_TRUE(outputControlTimestamp.setISO8601Format(false));
+  EXPECT_FALSE(outputControlTimestamp.iso8601Format());
+
+  EXPECT_FALSE(outputControlTimestamp.timestampAtBeginningOfInterval());
+  EXPECT_TRUE(outputControlTimestamp.setTimestampAtBeginningOfInterval(true));
+  EXPECT_TRUE(outputControlTimestamp.timestampAtBeginningOfInterval());
+  EXPECT_TRUE(outputControlTimestamp.setTimestampAtBeginningOfInterval(false));
+  EXPECT_FALSE(outputControlTimestamp.timestampAtBeginningOfInterval());
+}
diff --git a/src/model/test/UniqueModelObject_GTest.cpp b/src/model/test/UniqueModelObject_GTest.cpp
index 97ae8235fda..0b3ed6f34e8 100644
--- a/src/model/test/UniqueModelObject_GTest.cpp
+++ b/src/model/test/UniqueModelObject_GTest.cpp
@@ -60,6 +60,8 @@
 #include "../OutputControlReportingTolerances_Impl.hpp"
 #include "../OutputControlTableStyle.hpp"
 #include "../OutputControlTableStyle_Impl.hpp"
+#include "../OutputControlTimestamp.hpp"
+#include "../OutputControlTimestamp_Impl.hpp"
 #include "../OutputDebuggingData.hpp"
 #include "../OutputDebuggingData_Impl.hpp"
 #include "../OutputDiagnostics.hpp"
@@ -422,6 +424,31 @@ TEST_F(ModelFixture, OutputControlTableStyle_UniqueModelObject_Clone) {
   EXPECT_EQ("! Custom Object", outputControlTableStyleClone2.comment());
 }
 
+TEST_F(ModelFixture, OutputControlTimestamp_UniqueModelObject_Clone) {
+  // create a model to use
+  Model model;
+
+  // Get the Unique ModelObject
+  EXPECT_FALSE(model.getOptionalUniqueModelObject<OutputControlTimestamp>());
+  OutputControlTimestamp outputControlTimestamp = model.getUniqueModelObject<OutputControlTimestamp>();
+  EXPECT_TRUE(model.getOptionalUniqueModelObject<OutputControlTimestamp>());
+  // We use a comment to see if cloning to another model works
+  outputControlTimestamp.setComment("Custom Object");
+
+  // clone it into same model
+  auto outputControlTimestampClone = outputControlTimestamp.clone(model).cast<OutputControlTimestamp>();
+  // UniqueModelObject: should be the same as the original
+  EXPECT_EQ(outputControlTimestamp, outputControlTimestampClone);
+  EXPECT_EQ("! Custom Object", outputControlTimestampClone.comment());
+
+  // clone it into a different model
+  Model model2;
+  EXPECT_FALSE(model2.getOptionalUniqueModelObject<OutputControlTimestamp>());
+  auto outputControlTimestampClone2 = outputControlTimestamp.clone(model2).cast<OutputControlTimestamp>();
+  EXPECT_TRUE(model2.getOptionalUniqueModelObject<OutputControlTimestamp>());
+  EXPECT_EQ("! Custom Object", outputControlTimestampClone2.comment());
+}
+
 TEST_F(ModelFixture, OutputDebuggingData_UniqueModelObject_Clone) {
   // create a model to use
   Model model;