Repository: NREL/OpenStudio (language: python)

Issue:
ScheduleDay::getValue applies interpolation differently than EnergyPlus
Issue overview
--------------
For a ScheduleDay with 'Interpolate to Timestep' = 'Yes', calling [`getValue`](https://github.com/NREL/OpenStudio/blob/7a987d3fa223bd8319aac2e09db9ff7ce09a9258/src/model/ScheduleDay.cpp#L174) 
 with a Time value that does not equal one of the scheduled Hour+Minute values will return an interpolated value, which is inconsistent with how EnergyPlus interprets that input.

## Current Behavior
EnergyPlus interprets '[Interpolate to Timestep](https://bigladdersoftware.com/epx/docs/23-2/input-output-reference/group-schedules.html#field-interpolate-to-timestep)' = 'Average' to mean "when the simulation timestep doesn't coincide with the scheduled interval, the value at the intermediate timestep is interpolated".  I.e., for this schedule: 
```
Schedule:Day:Interval,
    Day Schedule,            !- Name
    Fractional,              !- Schedule Type Limits Name
    Average,                 !- Interpolate to Timestep
    8:15,            	     !- Time 1 {hh:mm}
    0,                       !- Value Until Time 1
    21:45,                   !- Time 2 {hh:mm}
    1,                       !- Value Until Time 2
    24:00,                   !- Time 3 {hh:mm}
    0;                       !- Value Until Time 3
```
If the simulation timesteps per hour are 4, will evaluate like: 
![image](https://github.com/NREL/OpenStudio/assets/10799524/15b428d8-ecb8-4b10-9e4b-00f9cd90b044)

With 'Average' interpolation, for 10 timesteps per hour, it would evaluate like: 
![image](https://github.com/NREL/OpenStudio/assets/10799524/c1159232-9e79-46d3-9618-bb192c29a1fe)

However `ScheduleDay::getValue` in OpenStudio **interpolates between schedule times** (i.e., 8:15 to 21:45), so calling `getValue` with intermediate times results in a plot like this: 
![image](https://github.com/NREL/OpenStudio/assets/10799524/197cfe26-51ad-4e2e-8b21-70286356dcdc)

## Expected Behavior
I expect `getValue` to return the same value that EnergyPlus would for a schedule at a given time.

## Steps to Reproduce
Create a ScheduleDay with 'Interpolate To Timestep' = 'Yes', and make successive calls to `getValue` like: 
```
def print_vals(sch)
  (0..24).each do |hr|
    ["00","15","30","45"].each do |min|
      hr_pad = "%02d" % hr
      time = OpenStudio::Time.new("#{hr_pad}:#{min}:00")
      val = day_sch.getValue(time)
      puts "#{time}, #{val}"
    end
  end
end

model = OpenStudio::Model::Model.new
sch = OpenStudio::Model::ScheduleDay.new(model)
sch.setInterpolatetoTimestep(true)
sch.addValue(OpenStudio::Time.new("08:15:00"),0)
sch.addValue(OpenStudio::Time.new("21:45:00"),1)
print_vals(sch)

```
-> ...
08:00:00, 0.0
08:15:00, 0.0
08:30:00, 0.01851851851851845
08:45:00, 0.03703703703703701
09:00:00, 0.05555555555555555
...
21:00:00, 0.9444444444444444
21:15:00, 0.9629629629629629
21:30:00, 0.9814814814814814
21:45:00, 1.0
22:00:00, 0.8888888888888893
22:15:00, 0.7777777777777786


Some additional details about your environment for this issue (if relevant):
 - Platform (Operating system, version): all
 - Version of OpenStudio (if using an intermediate build, include SHA): 3.6.1 but this goes back a long ways

### Context
This impacts multiple uses of `getValue`, e.g. for determining HVAC occupancy schedules in [openstudio-standards](https://github.com/NREL/openstudio-standards/blob/682d3b2187d541fdeb91949e5bacbc6bc83952ff/lib/openstudio-standards/standards/Standards.ThermalZone.rb#L345), schedule reporting in [OpenStudio Results](https://github.com/NREL/openstudio-common-measures-gem/blob/0e3558cf96b446e8a6f5041ae21cc1fd93bc4661/lib/measures/openstudio_results/resources/os_lib_reporting.rb#L4657), etc. 



Discussion / hints:
For users, is the alternative/workaround here to add every single value to the day schedule for all timesteps?
@joseph-robertson I suppose. Alternatively, the user could store the value of `interpolatetoTimestep`, set it to `false` before calling `getValue`, and reset it after. That still wouldn't exactly match EnergyPlus, but would be closer than the existing implementation.
@joseph-robertson 
> For users, is the alternative/workaround here to add every single value to the day schedule for all timesteps?

How about a new OS:ScheduleDay method `getValuesatTimestep(OS:Timestep)` that returns a vector of schedule values, which you could then interpolate for a given OS:Time? It would be useful to replace [this standards method](https://github.com/NREL/openstudio-standards/blob/67fce3bce8507c710a978f1dfe591114fa67e37d/lib/openstudio-standards/schedules/information.rb#L337), and (ideally) extend it up to ScheduleRuleset, like [this](https://github.com/NREL/openstudio-standards/blob/67fce3bce8507c710a978f1dfe591114fa67e37d/lib/openstudio-standards/schedules/information.rb#L591)

@DavidGoldwasser @mdahlhausen 

Fix patch:
diff --git a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md
index a232fe46b1f..63a8e31bcee 100644
--- a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md
+++ b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md
@@ -86,6 +86,10 @@ For a list of deprecated and removed methods, please refer to [deprecated_method
     * A number of methods have been renamed (and the old ones deprecated) to conform to the API for other `SpaceLoadInstance` / `SpaceLoadDefinition` objects
     * Mostly `getWattsperUnit` is changed to `getDesignLevel` and `getWattsperZoneFloorArea` is changed to `getPowerPerFloorArea`
     * Refer to [deprecated_methods.csv](../../ruby/deprecated_methods.csv) for the complete list
+* [#5111](https://github.com/NREL/OpenStudio/pull/5111) - ScheduleDay: new timeseries method and interpolation options
+    * The `ScheduleDay` has API-breaking changes related to setters and getters for its `Interpolate To Timestep` field. They now use `string` rather than `bool` to conform to the IDD type `\choice`
+    * The forward translator for `ScheduleDay` replaces always setting "Average" with the interpolation method stored in `Interpolate to Timestep` field
+    * A new `timeseries()` method is introduced for returning vectors of times and (interpolated) values for the given number of timesteps per hour established by the `Timestep` object; `getValue` references this vector for an interpolated value at a given time
 
 ## Minor changes and bug fixes
 
diff --git a/resources/model/OpenStudio.idd b/resources/model/OpenStudio.idd
index d9b314c5b7b..105e0d2169f 100644
--- a/resources/model/OpenStudio.idd
+++ b/resources/model/OpenStudio.idd
@@ -4594,12 +4594,13 @@ OS:Schedule:Day,
        \type object-list
        \object-list ScheduleTypeLimitsNames
   A4, \field Interpolate to Timestep
-       \note when the interval does not match the user specified timestep a Yes choice will average between the intervals request (to
-       \note timestep resolution.  a No choice will use the interval value at the simulation timestep without regard to if it matches
-       \note the boundary or not.
+       \note when the interval does not match the user specified timestep a Average choice will average between the intervals request (to
+       \note timestep resolution. A No choice will use the interval value at the simulation timestep without regard to if it matches
+       \note the boundary or not. A Linear choice will interpolate linearly between successive values.
        \type choice
        \default No
-       \key Yes
+       \key Average
+       \key Linear
        \key No
   N1, \field Hour
        \type integer
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateScheduleDay.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateScheduleDay.cpp
index f4a15c27a48..960598b4172 100644
--- a/src/energyplus/ForwardTranslator/ForwardTranslateScheduleDay.cpp
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateScheduleDay.cpp
@@ -39,11 +39,7 @@ namespace energyplus {
       }
     }
 
-    if (modelObject.interpolatetoTimestep()) {
-      scheduleDay.setString(Schedule_Day_IntervalFields::InterpolatetoTimestep, "Average");
-    } else {
-      scheduleDay.setString(Schedule_Day_IntervalFields::InterpolatetoTimestep, "No");
-    }
+    scheduleDay.setString(Schedule_Day_IntervalFields::InterpolatetoTimestep, modelObject.interpolatetoTimestep());
 
     std::vector<double> values = modelObject.values();
     std::vector<openstudio::Time> times = modelObject.times();
diff --git a/src/energyplus/ReverseTranslator/ReverseTranslateScheduleDayInterval.cpp b/src/energyplus/ReverseTranslator/ReverseTranslateScheduleDayInterval.cpp
index 69a76331a3d..59e88bce0fc 100644
--- a/src/energyplus/ReverseTranslator/ReverseTranslateScheduleDayInterval.cpp
+++ b/src/energyplus/ReverseTranslator/ReverseTranslateScheduleDayInterval.cpp
@@ -50,13 +50,7 @@ namespace energyplus {
 
     s = workspaceObject.getString(Schedule_Day_IntervalFields::InterpolatetoTimestep);
     if (s) {
-      if (openstudio::istringEqual(*s, "No")) {
-        scheduleDay.setInterpolatetoTimestep(false);
-      } else if (openstudio::istringEqual(*s, "Linear")) {
-        scheduleDay.setInterpolatetoTimestep(true);
-      } else if (openstudio::istringEqual(*s, "Average")) {
-        scheduleDay.setInterpolatetoTimestep(true);
-      }
+      scheduleDay.setInterpolatetoTimestep(*s);
     }
 
     //get extensible groups
diff --git a/src/energyplus/Test/ScheduleRuleset_GTest.cpp b/src/energyplus/Test/ScheduleRuleset_GTest.cpp
index 946fa1bbe99..e3e0ea7b611 100644
--- a/src/energyplus/Test/ScheduleRuleset_GTest.cpp
+++ b/src/energyplus/Test/ScheduleRuleset_GTest.cpp
@@ -698,7 +698,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekDailyToRulesetSimple
   EXPECT_EQ(0, scheduleRule.ruleIndex());
   ScheduleDay daySchedule = scheduleRule.daySchedule();
   EXPECT_EQ(daySchedule.nameString(), "occupants schedule allday1 1");
-  EXPECT_FALSE(daySchedule.interpolatetoTimestep());
+  EXPECT_EQ("No", daySchedule.interpolatetoTimestep());
   EXPECT_EQ(8u, daySchedule.values().size());
   EXPECT_TRUE(scheduleRule.applySunday());
   EXPECT_TRUE(scheduleRule.applyMonday());
@@ -864,7 +864,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekDailyToRulesetComple
   EXPECT_EQ(2, scheduleRule1.ruleIndex());
   ScheduleDay daySchedule1 = scheduleRule1.daySchedule();
   EXPECT_EQ(daySchedule1.nameString(), "occupants schedule allday1 1");
-  EXPECT_FALSE(daySchedule1.interpolatetoTimestep());
+  EXPECT_EQ("No", daySchedule1.interpolatetoTimestep());
   EXPECT_EQ(8u, daySchedule1.values().size());
   EXPECT_TRUE(scheduleRule1.applySunday());
   EXPECT_TRUE(scheduleRule1.applyMonday());
@@ -888,7 +888,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekDailyToRulesetComple
   EXPECT_EQ(1, scheduleRule2.ruleIndex());
   ScheduleDay daySchedule2 = scheduleRule2.daySchedule();
   EXPECT_EQ(daySchedule2.nameString(), "occupants schedule allday1 2");
-  EXPECT_FALSE(daySchedule2.interpolatetoTimestep());
+  EXPECT_EQ("No", daySchedule2.interpolatetoTimestep());
   EXPECT_EQ(8u, daySchedule2.values().size());
   EXPECT_TRUE(scheduleRule2.applySunday());
   EXPECT_TRUE(scheduleRule2.applyMonday());
@@ -912,7 +912,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekDailyToRulesetComple
   EXPECT_EQ(0, scheduleRule3.ruleIndex());
   ScheduleDay daySchedule3 = scheduleRule3.daySchedule();
   EXPECT_EQ(daySchedule3.nameString(), "occupants schedule allday2 1");
-  EXPECT_FALSE(daySchedule3.interpolatetoTimestep());
+  EXPECT_EQ("No", daySchedule3.interpolatetoTimestep());
   EXPECT_EQ(8u, daySchedule3.values().size());
   EXPECT_FALSE(scheduleRule3.applySunday());
   EXPECT_FALSE(scheduleRule3.applyMonday());
@@ -1220,7 +1220,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekCompactToRulesetComp
   EXPECT_EQ(2, scheduleRule1.ruleIndex());
   ScheduleDay daySchedule1 = scheduleRule1.daySchedule();
   EXPECT_EQ(daySchedule1.nameString(), "occupants schedule allday1 1");
-  EXPECT_FALSE(daySchedule1.interpolatetoTimestep());
+  EXPECT_EQ("No", daySchedule1.interpolatetoTimestep());
   EXPECT_EQ(8u, daySchedule1.values().size());
   EXPECT_TRUE(scheduleRule1.applySunday());
   EXPECT_TRUE(scheduleRule1.applyMonday());
@@ -1244,7 +1244,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekCompactToRulesetComp
   EXPECT_EQ(1, scheduleRule2.ruleIndex());
   ScheduleDay daySchedule2 = scheduleRule2.daySchedule();
   EXPECT_EQ(daySchedule2.nameString(), "occupants schedule allday1 2");
-  EXPECT_FALSE(daySchedule2.interpolatetoTimestep());
+  EXPECT_EQ("No", daySchedule2.interpolatetoTimestep());
   EXPECT_EQ(8u, daySchedule2.values().size());
   EXPECT_TRUE(scheduleRule2.applySunday());
   EXPECT_TRUE(scheduleRule2.applyMonday());
@@ -1268,7 +1268,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekCompactToRulesetComp
   EXPECT_EQ(0, scheduleRule3.ruleIndex());
   ScheduleDay daySchedule3 = scheduleRule3.daySchedule();
   EXPECT_EQ(daySchedule3.nameString(), "occupants schedule allday2 1");
-  EXPECT_FALSE(daySchedule3.interpolatetoTimestep());
+  EXPECT_EQ("No", daySchedule3.interpolatetoTimestep());
   EXPECT_EQ(8u, daySchedule3.values().size());
   EXPECT_FALSE(scheduleRule3.applySunday());
   EXPECT_FALSE(scheduleRule3.applyMonday());
diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp
index 66ddbc97a05..5efe02d0fc5 100644
--- a/src/model/ScheduleDay.cpp
+++ b/src/model/ScheduleDay.cpp
@@ -16,6 +16,8 @@
 #include "ScheduleRuleset_Impl.hpp"
 #include "ScheduleRule.hpp"
 #include "ScheduleRule_Impl.hpp"
+#include "Timestep.hpp"
+#include "Timestep_Impl.hpp"
 
 #include "../utilities/idf/IdfExtensibleGroup.hpp"
 #include <utilities/idd/OS_Schedule_Day_FieldEnums.hxx>
@@ -25,6 +27,7 @@
 #include "../utilities/core/Assert.hpp"
 
 #include "../utilities/time/Time.hpp"
+#include "../utilities/data/TimeSeries.hpp"
 #include "../utilities/data/Vector.hpp"
 
 namespace openstudio {
@@ -115,8 +118,10 @@ namespace model {
       return !getObject<ScheduleDay>().getModelObjectTarget<ScheduleTypeLimits>(OS_Schedule_DayFields::ScheduleTypeLimitsName);
     }
 
-    bool ScheduleDay_Impl::interpolatetoTimestep() const {
-      return getBooleanFieldValue(OS_Schedule_DayFields::InterpolatetoTimestep);
+    std::string ScheduleDay_Impl::interpolatetoTimestep() const {
+      boost::optional<std::string> value = getString(OS_Schedule_DayFields::InterpolatetoTimestep, true);
+      OS_ASSERT(value);
+      return value.get();
     }
 
     bool ScheduleDay_Impl::isInterpolatetoTimestepDefaulted() const {
@@ -176,42 +181,132 @@ namespace model {
         return 0.0;
       }
 
-      std::vector<double> values = this->values();          // these are already sorted
-      std::vector<openstudio::Time> times = this->times();  // these are already sorted
+      // We'll calculate the entire day when we request a single value but that's on purpose:
+      // * We're talking about max 60 timesteps * 24 hours = 1440 points,
+      //   but realistically more often than not you'll have a timestep of 6 (our default) or 4 so 96 to 144 points. So not a lot of points
+      // * We cache the timeSeries, and,
+      // * More often than not, the use case is to do it for the entire day anyways (eg: openstudio-standards to determine occupancy schedules)
+      TimeSeries ts = this->timeSeries();
 
-      unsigned N = times.size();
+      DateTimeVector dateTimes = ts.dateTimes();
+      Vector values = ts.values();
+
+      const unsigned N = dateTimes.size();
       OS_ASSERT(values.size() == N);
 
       if (N == 0) {
         return 0.0;
       }
 
-      openstudio::Vector x(N + 2);
-      openstudio::Vector y(N + 2);
-
-      x[0] = -0.000001;
-      y[0] = 0.0;
+      Vector x(N + 2);
+      Vector y(N + 2);
+
+      x[0] = 0.0;
+      std::string interpolatetoTimestep = this->interpolatetoTimestep();
+      if (istringEqual("No", interpolatetoTimestep)) {
+        y[0] = values[0];
+      } else if (istringEqual("Average", interpolatetoTimestep)) {
+        y[0] = values[0];
+      } else if (istringEqual("Linear", interpolatetoTimestep)) {
+        y[0] = 0.0;
+      }
 
       for (unsigned i = 0; i < N; ++i) {
-        x[i + 1] = times[i].totalDays();
+        openstudio::Time t = dateTimes[i].time();
+        if (t.totalDays() == 0.0) {  // this is 00:00:00 from the next day
+          t = openstudio::Time(0, 24, 0);
+        }
+
+        x[i + 1] = t.totalDays();
         y[i + 1] = values[i];
       }
 
-      x[N + 1] = 1.000001;
-      y[N + 1] = 0.0;
+      x[N + 1] = 1.0;
+      y[N + 1] = values[N - 1];
 
-      InterpMethod interpMethod;
-      if (this->interpolatetoTimestep()) {
-        interpMethod = LinearInterp;
-      } else {
-        interpMethod = HoldNextInterp;
-      }
-
-      double result = interp(x, y, time.totalDays(), interpMethod, NoneExtrap);
+      double result = interp(x, y, time.totalDays(), HoldNextInterp, NoneExtrap);
 
       return result;
     }
 
+    openstudio::TimeSeries ScheduleDay_Impl::timeSeries() const {
+      if (!m_cachedTimeSeries) {
+
+        int numberOfTimestepsPerHour;
+        if (boost::optional<Timestep> timestep = this->model().getOptionalUniqueModelObject<Timestep>()) {
+          numberOfTimestepsPerHour = timestep->numberOfTimestepsPerHour();
+        } else {
+          numberOfTimestepsPerHour = 6;
+        }
+
+        Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1));  // this is arbitrary
+        int minutes = 60 / numberOfTimestepsPerHour;
+        DateTime startDateTime(startDate, Time(0, 0, 0));
+
+        DateTimeVector tsDateTimes;
+        for (size_t hour = 0; hour < 24; ++hour) {
+          for (size_t minute = minutes; minute <= 60; minute += minutes) {
+            if (minute == 60) {
+              openstudio::Time t(0, hour + 1, 0);
+              tsDateTimes.push_back(startDateTime + t);
+            } else {
+              openstudio::Time t(0, hour, minute);
+              tsDateTimes.push_back(startDateTime + t);
+            }
+          }
+        }
+
+        std::vector<double> values = this->values();          // these are already sorted
+        std::vector<openstudio::Time> times = this->times();  // these are already sorted
+
+        const unsigned N = times.size();
+        OS_ASSERT(values.size() == N);
+
+        TimeSeries result;
+        if (N == 0) {
+          return result;
+        }
+
+        Vector x(N + 2);
+        Vector y(N + 2);
+
+        x[0] = -0.000001;
+        y[0] = 0.0;
+
+        for (unsigned i = 0; i < N; ++i) {
+          x[i + 1] = times[i].totalSeconds();
+          y[i + 1] = values[i];
+        }
+
+        x[N + 1] = 86400.000001;
+        y[N + 1] = 0.0;
+
+        std::string interpolatetoTimestep = this->interpolatetoTimestep();
+        Vector tsValues(tsDateTimes.size());
+        for (unsigned j = 0; j < tsDateTimes.size(); ++j) {
+          openstudio::Time t = tsDateTimes[j].time();
+          if (t.totalDays() == 0.0) {  // this is 00:00:00 from the next day
+            t = openstudio::Time(0, 24, 0);
+          }
+
+          if (istringEqual("No", interpolatetoTimestep)) {
+            tsValues[j] = interp(x, y, t.totalSeconds(), HoldNextInterp, NoneExtrap);
+          } else if (istringEqual("Average", interpolatetoTimestep)) {
+            double minutes = 60.0 / numberOfTimestepsPerHour;
+            double ti = minutes * 60.0;  // total seconds of the timestep interval
+            tsValues[j] = interp(x, y, t.totalSeconds(), AverageInterp, NoneExtrap, ti);
+          } else if (istringEqual("Linear", interpolatetoTimestep)) {
+            tsValues[j] = interp(x, y, t.totalSeconds(), LinearInterp, NoneExtrap);
+          }
+        }
+
+        result = TimeSeries(tsDateTimes, tsValues, "");
+        m_cachedTimeSeries = result;
+      }
+
+      return m_cachedTimeSeries.get();
+    }
+
     bool ScheduleDay_Impl::setScheduleTypeLimits(const ScheduleTypeLimits& scheduleTypeLimits) {
       if (scheduleTypeLimits.model() != model()) {
         return false;
@@ -229,9 +324,8 @@ namespace model {
       return false;
     }
 
-    bool ScheduleDay_Impl::setInterpolatetoTimestep(bool interpolatetoTimestep) {
-      return setBooleanFieldValue(OS_Schedule_DayFields::InterpolatetoTimestep, interpolatetoTimestep);
-      ;
+    bool ScheduleDay_Impl::setInterpolatetoTimestep(const std::string& interpolatetoTimestep) {
+      return setString(OS_Schedule_DayFields::InterpolatetoTimestep, interpolatetoTimestep);
     }
 
     void ScheduleDay_Impl::resetInterpolatetoTimestep() {
@@ -369,6 +463,11 @@ namespace model {
     void ScheduleDay_Impl::clearCachedVariables() {
       m_cachedTimes.reset();
       m_cachedValues.reset();
+      m_cachedTimeSeries.reset();
+    }
+
+    void ScheduleDay_Impl::clearCachedTimeSeries() {
+      m_cachedTimeSeries.reset();
     }
 
   }  // namespace detail
@@ -394,7 +493,7 @@ namespace model {
     return getImpl<detail::ScheduleDay_Impl>()->isScheduleTypeLimitsDefaulted();
   }
 
-  bool ScheduleDay::interpolatetoTimestep() const {
+  std::string ScheduleDay::interpolatetoTimestep() const {
     return getImpl<detail::ScheduleDay_Impl>()->interpolatetoTimestep();
   }
 
@@ -414,7 +513,11 @@ namespace model {
     return getImpl<detail::ScheduleDay_Impl>()->getValue(time);
   }
 
-  bool ScheduleDay::setInterpolatetoTimestep(bool interpolatetoTimestep) {
+  openstudio::TimeSeries ScheduleDay::timeSeries() const {
+    return getImpl<detail::ScheduleDay_Impl>()->timeSeries();
+  }
+
+  bool ScheduleDay::setInterpolatetoTimestep(const std::string& interpolatetoTimestep) {
     return getImpl<detail::ScheduleDay_Impl>()->setInterpolatetoTimestep(interpolatetoTimestep);
   }
 
diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp
index ce64172a47e..70feeba5e18 100644
--- a/src/model/ScheduleDay.hpp
+++ b/src/model/ScheduleDay.hpp
@@ -54,7 +54,7 @@ namespace model {
    *  inherits one from a Schedule. */
     bool isScheduleTypeLimitsDefaulted() const;
 
-    bool interpolatetoTimestep() const;
+    std::string interpolatetoTimestep() const;
 
     bool isInterpolatetoTimestepDefaulted() const;
 
@@ -66,14 +66,18 @@ namespace model {
     /// Returns a vector of values in the same order and with the same number of elements as times.
     std::vector<double> values() const;
 
-    /// Returns the value in effect at the given time.  If time is less than 0 days or greater than 1 day, 0 is returned.
+    /// Returns the value in effect at the given time.
+    /// If time is less than 0 days or greater than 1 day, 0 is returned.
     double getValue(const openstudio::Time& time) const;
 
+    /// Returns the timeseries corresponding to simulation timestep and chosen interpolation method.
+    openstudio::TimeSeries timeSeries() const;
+
     //@}
     /** @name Setters */
     //@{
 
-    bool setInterpolatetoTimestep(bool interpolatetoTimestep);
+    bool setInterpolatetoTimestep(const std::string& interpolatetoTimestep);
 
     void resetInterpolatetoTimestep();
 
diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp
index 564fec1a279..ff704c4ac07 100644
--- a/src/model/ScheduleDay_Impl.hpp
+++ b/src/model/ScheduleDay_Impl.hpp
@@ -10,15 +10,20 @@
 #include "ScheduleBase_Impl.hpp"
 
 #include "../utilities/time/Time.hpp"
+#include "../utilities/data/TimeSeries.hpp"
 
 namespace openstudio {
 
+class TimeSeries;
+
 namespace model {
 
   class ScheduleTypeLimits;
 
   namespace detail {
 
+    class Timestep_Impl;
+
     /** ScheduleDay_Impl is a ResourceObject_Impl that is the implementation class for ScheduleDay.*/
     class MODEL_API ScheduleDay_Impl : public ScheduleBase_Impl
     {
@@ -57,7 +62,7 @@ namespace model {
 
       bool isScheduleTypeLimitsDefaulted() const;
 
-      bool interpolatetoTimestep() const;
+      std::string interpolatetoTimestep() const;
 
       bool isInterpolatetoTimestepDefaulted() const;
 
@@ -69,9 +74,13 @@ namespace model {
       /// Returns a vector of values in the same order and with the same number of elements as times.
       virtual std::vector<double> values() const override;
 
-      /// Returns the value in effect at the given time.  If time is less than 0 days or greater than 1 day, 0 is returned.
+      /// Returns the value in effect at the given time.
+      /// If time is less than 0 days or greater than 1 day, 0 is returned.
       double getValue(const openstudio::Time& time) const;
 
+      /// Returns the timeseries corresponding to simulation timestep and chosen interpolation method.
+      openstudio::TimeSeries timeSeries() const;
+
       //@}
       /** @name Setters */
       //@{
@@ -80,7 +89,7 @@ namespace model {
 
       virtual bool resetScheduleTypeLimits() override;
 
-      bool setInterpolatetoTimestep(bool interpolatetoTimestep);
+      bool setInterpolatetoTimestep(const std::string& interpolatetoTimestep);
 
       void resetInterpolatetoTimestep();
 
@@ -104,6 +113,9 @@ namespace model {
 
       virtual bool okToResetScheduleTypeLimits() const override;
 
+      friend class Timestep_Impl;
+      void clearCachedTimeSeries();
+
       //private slots:
      private:
       void clearCachedVariables();
@@ -113,6 +125,7 @@ namespace model {
 
       mutable boost::optional<std::vector<openstudio::Time>> m_cachedTimes;
       mutable boost::optional<std::vector<double>> m_cachedValues;
+      mutable boost::optional<openstudio::TimeSeries> m_cachedTimeSeries;
     };
 
   }  // namespace detail
diff --git a/src/model/Timestep.cpp b/src/model/Timestep.cpp
index 90b803e3355..77bfd6b81f0 100644
--- a/src/model/Timestep.cpp
+++ b/src/model/Timestep.cpp
@@ -9,6 +9,8 @@
 #include "SimulationControl_Impl.hpp"
 #include "Model.hpp"
 #include "Model_Impl.hpp"
+#include "ScheduleDay.hpp"
+#include "ScheduleDay_Impl.hpp"
 #include "../utilities/core/Assert.hpp"
 #include <utilities/idd/OS_Timestep_FieldEnums.hxx>
 #include <utilities/idd/IddEnums.hxx>
@@ -66,11 +68,19 @@ namespace model {
     }
 
     bool Timestep_Impl::setNumberOfTimestepsPerHour(int numberOfTimestepsPerHour) {
+      if (numberOfTimestepsPerHour != this->numberOfTimestepsPerHour()) {
+        for (auto& sch_day : model().getConcreteModelObjects<ScheduleDay>()) {
+          sch_day.getImpl<ScheduleDay_Impl>()->clearCachedTimeSeries();
+        }
+      }
       bool result = setInt(OS_TimestepFields::NumberofTimestepsperHour, numberOfTimestepsPerHour);
       return result;
     }
 
     void Timestep_Impl::resetNumberOfTimestepsPerHour() {
+      for (auto& sch_day : model().getConcreteModelObjects<ScheduleDay>()) {
+        sch_day.getImpl<ScheduleDay_Impl>()->clearCachedTimeSeries();
+      }
       bool result = setString(OS_TimestepFields::NumberofTimestepsperHour, "");
       OS_ASSERT(result);
     }
diff --git a/src/osversion/VersionTranslator.cpp b/src/osversion/VersionTranslator.cpp
index ad7436325f7..b4c7b138e15 100644
--- a/src/osversion/VersionTranslator.cpp
+++ b/src/osversion/VersionTranslator.cpp
@@ -9160,6 +9160,32 @@ namespace osversion {
         ss << newObject;
         m_refactored.emplace_back(std::move(object), std::move(newObject));
 
+      } else if (iddname == "OS:Schedule:Day") {
+
+        // 1 Field has been modified from 3.7.0 to 3.8.0:
+        // ----------------------------------------------
+        // * Interpolate to Timestep * 3 - Changed from bool to string choice
+
+        auto iddObject = idd_3_8_0.getObject(iddname);
+        IdfObject newObject(iddObject.get());
+
+        for (size_t i = 0; i < object.numFields(); ++i) {
+          if ((value = object.getString(i))) {
+            if (i == 3) {
+              if (istringEqual(value.get(), "Yes")) {
+                newObject.setString(3, "Average");
+              } else {
+                newObject.setString(3, "No");
+              }
+            } else {
+              newObject.setString(i, value.get());
+            }
+          }
+        }
+
+        ss << newObject;
+        m_refactored.emplace_back(std::move(object), std::move(newObject));
+
         // No-op
       } else {
         ss << object;
diff --git a/src/utilities/data/Matrix.cpp b/src/utilities/data/Matrix.cpp
index 41d6293894b..30d1a80e62f 100644
--- a/src/utilities/data/Matrix.cpp
+++ b/src/utilities/data/Matrix.cpp
@@ -38,7 +38,8 @@ bool operator!=(const Matrix& lhs, const Matrix& rhs) {
 
 /// linear interpolation of the function v = f(x, y) at point xi, yi
 /// assumes that x and y are strictly increasing
-double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod) {
+double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod,
+              double ti) {
   double result = 0.0;
 
   size_t M = x.size();
@@ -48,7 +49,7 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub
     return result;
   }
 
-  InterpInfo xInfo = interpInfo(x, xi);
+  InterpInfo xInfo = interpInfo(x, xi, ti);
 
   if (xInfo.extrapolated) {
     switch (extrapMethod) {
@@ -68,6 +69,10 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub
         // linear interpolation
         // no-op
         break;
+      case AverageInterp:
+        // average interpolation
+        // no-op
+        break;
       case NearestInterp:
         // pick closest point
         if (xInfo.wa > xInfo.wb) {
@@ -91,7 +96,7 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub
     }
   }
 
-  InterpInfo yInfo = interpInfo(y, yi);
+  InterpInfo yInfo = interpInfo(y, yi, ti);
 
   if (yInfo.extrapolated) {
     switch (extrapMethod) {
@@ -111,6 +116,10 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub
         // linear interpolation
         // no-op
         break;
+      case AverageInterp:
+        // average interpolation
+        // no-op
+        break;
       case NearestInterp:
         // pick closest point
         if (yInfo.wa > yInfo.wb) {
@@ -143,7 +152,8 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub
 
 /// linear interpolation of the function v = f(x, y) at points xi, yi
 /// assumes that x and y are strictly increasing
-Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod) {
+Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod,
+              double ti) {
   size_t M = x.size();
 
   Vector result(M);
@@ -153,7 +163,7 @@ Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& x
   }
 
   for (unsigned i = 0; i < M; ++i) {
-    result(i) = interp(x, y, v, xi(i), yi, interpMethod, extrapMethod);
+    result(i) = interp(x, y, v, xi(i), yi, interpMethod, extrapMethod, ti);
   }
 
   return result;
@@ -161,7 +171,8 @@ Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& x
 
 /// linear interpolation of the function v = f(x, y) at points xi, yi
 /// assumes that x and y are strictly increasing
-Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, const Vector& yi, InterpMethod interpMethod, ExtrapMethod extrapMethod) {
+Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, const Vector& yi, InterpMethod interpMethod, ExtrapMethod extrapMethod,
+              double ti) {
   size_t N = y.size();
 
   Vector result(N);
@@ -171,7 +182,7 @@ Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, cons
   }
 
   for (unsigned j = 0; j < N; ++j) {
-    result(j) = interp(x, y, v, xi, yi(j), interpMethod, extrapMethod);
+    result(j) = interp(x, y, v, xi, yi(j), interpMethod, extrapMethod, ti);
   }
 
   return result;
@@ -180,7 +191,7 @@ Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, cons
 /// linear interpolation of the function v = f(x, y) at points xi, yi
 /// assumes that x and y are strictly increasing
 Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, const Vector& yi, InterpMethod interpMethod,
-              ExtrapMethod extrapMethod) {
+              ExtrapMethod extrapMethod, double ti) {
   size_t M = x.size();
   size_t N = y.size();
 
@@ -192,7 +203,7 @@ Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& x
 
   for (unsigned i = 0; i < M; ++i) {
     for (unsigned j = 0; j < N; ++j) {
-      result(i, j) = interp(x, y, v, xi(i), yi(j), interpMethod, extrapMethod);
+      result(i, j) = interp(x, y, v, xi(i), yi(j), interpMethod, extrapMethod, ti);
     }
   }
 
diff --git a/src/utilities/data/Matrix.hpp b/src/utilities/data/Matrix.hpp
index 136224348b1..ecf6a9b0508 100644
--- a/src/utilities/data/Matrix.hpp
+++ b/src/utilities/data/Matrix.hpp
@@ -32,23 +32,31 @@ UTILITIES_API bool operator!=(const Matrix& lhs, const Matrix& rhs);
 
 /// linear interpolation of the function v = f(x, y) at point xi, yi
 /// assumes that x and y are strictly increasing
+/// ti is the total seconds of the timestep interval; it is used for
+/// AverageInterp and must be positive
 UTILITIES_API double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod = LinearInterp,
-                            ExtrapMethod extrapMethod = NoneExtrap);
+                            ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0);
 
 /// linear interpolation of the function v = f(x, y) at points xi, yi
 /// assumes that x and y are strictly increasing
+/// ti is the total seconds of the timestep interval; it is used for
+/// AverageInterp and must be positive
 UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, double yi, InterpMethod interpMethod = LinearInterp,
-                            ExtrapMethod extrapMethod = NoneExtrap);
+                            ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0);
 
 /// linear interpolation of the function v = f(x, y) at points xi, yi
 /// assumes that x and y are strictly increasing
+/// ti is the total seconds of the timestep interval; it is used for
+/// AverageInterp and must be positive
 UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, const Vector& yi, InterpMethod interpMethod = LinearInterp,
-                            ExtrapMethod extrapMethod = NoneExtrap);
+                            ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0);
 
 /// linear interpolation of the function v = f(x, y) at points xi, yi
 /// assumes that x and y are strictly increasing
+/// ti is the total seconds of the timestep interval; it is used for
+/// AverageInterp and must be positive
 UTILITIES_API Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, const Vector& yi,
-                            InterpMethod interpMethod = LinearInterp, ExtrapMethod extrapMethod = NoneExtrap);
+                            InterpMethod interpMethod = LinearInterp, ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0);
 
 /// matrix product
 UTILITIES_API Matrix prod(const Matrix& lop, const Matrix& rop);
diff --git a/src/utilities/data/Matrix.i b/src/utilities/data/Matrix.i
index 504e55f6fd6..eb63e040636 100644
--- a/src/utilities/data/Matrix.i
+++ b/src/utilities/data/Matrix.i
@@ -138,11 +138,11 @@ public:
 
 /// linear interpolation of the function v = f(x, y) at point xi, yi
 /// assumes that x and y are strictly increasing
-double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod = linearInterp, ExtrapMethod extrapMethod = noneExtrap);
+double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod = linearInterp, ExtrapMethod extrapMethod = noneExtrap, double ti = 0.0);
 
 /// linear interpolation of the function v = f(x, y) at points xi, yi
 /// assumes that x and y are strictly increasing
-Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, const Vector& yi, InterpMethod interpMethod = linearInterp, ExtrapMethod extrapMethod = noneExtrap);
+Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, const Vector& yi, InterpMethod interpMethod = linearInterp, ExtrapMethod extrapMethod = noneExtrap, double ti = 0.0);
 
 /// outer product
 Matrix outerProd(const Vector& lhs, const Vector& rhs);
diff --git a/src/utilities/data/Vector.cpp b/src/utilities/data/Vector.cpp
index d96f302fe99..007c3271117 100644
--- a/src/utilities/data/Vector.cpp
+++ b/src/utilities/data/Vector.cpp
@@ -5,6 +5,8 @@
 
 #include "Vector.hpp"
 
+#include "../core/Assert.hpp"
+
 #include <random>
 
 // this should all be moved to a utilities/core/Random.h
@@ -54,7 +56,7 @@ bool operator!=(const Vector& lhs, const Vector& rhs) {
 
 /// linear interpolation of the function y = f(x) at point xi
 /// assumes that x is strictly increasing
-InterpInfo interpInfo(const Vector& x, double xi) {
+InterpInfo interpInfo(const Vector& x, double xi, double ti) {
   size_t N = x.size();
 
   InterpInfo result;
@@ -64,24 +66,28 @@ InterpInfo interpInfo(const Vector& x, double xi) {
     result.ib = 0;
     result.wa = 1.0;
     result.wb = 0.0;
+    result.ti = 1.0;
     result.extrapolated = false;
   } else if (xi < x(0)) {
     result.ia = 0;
     result.ib = 0;
     result.wa = 1.0;
     result.wb = 0.0;
+    result.ti = 1.0;
     result.extrapolated = true;
   } else if (x(N - 1) == xi) {
     result.ia = N - 1;
     result.ib = N - 1;
     result.wa = 0.0;
     result.wb = 1.0;
+    result.ti = 1.0;
     result.extrapolated = false;
   } else if (xi > x(N - 1)) {
     result.ia = N - 1;
     result.ib = N - 1;
     result.wa = 0.0;
     result.wb = 1.0;
+    result.ti = 1.0;
     result.extrapolated = true;
   } else {
 
@@ -92,8 +98,20 @@ InterpInfo interpInfo(const Vector& x, double xi) {
 
     result.ia = (unsigned)(it - begin - 1);
     result.ib = (unsigned)(it - begin);
-    result.wa = (x(result.ib) - xi) / (x(result.ib) - x(result.ia));
-    result.wb = (xi - x(result.ia)) / (x(result.ib) - x(result.ia));
+    if (ti < 0.0) {
+      result.wa = (x(result.ib) - xi) / (x(result.ib) - x(result.ia));
+      result.wb = (xi - x(result.ia)) / (x(result.ib) - x(result.ia));
+    } else {
+      result.wb = xi - x(result.ia);
+      result.wa = ti - result.wb;
+      if ((result.wb > 0.0) && (result.wb < ti)) {
+        result.ti = ti;
+      } else {
+        result.wa = 0.0;
+        result.wb = 1.0;
+        result.ti = 1.0;
+      }
+    }
   }
 
   return result;
@@ -101,7 +119,7 @@ InterpInfo interpInfo(const Vector& x, double xi) {
 
 /// linear interpolation of the function y = f(x) at point xi
 /// assumes that x is strictly increasing
-double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMethod, ExtrapMethod extrapMethod) {
+double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) {
 
   size_t N = x.size();
 
@@ -111,7 +129,11 @@ double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMe
     return result;
   }
 
-  InterpInfo info = interpInfo(x, xi);
+  if (interpMethod == AverageInterp && ti <= 0.0) {
+    LOG_FREE_AND_THROW("openstudio.Vector", "Value of ti must be positive when interpolating using the AverageInterp method.");
+  }
+
+  InterpInfo info = interpInfo(x, xi, ti);
 
   if (info.extrapolated) {
     switch (extrapMethod) {
@@ -130,6 +152,10 @@ double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMe
         // linear interpolation
         result = info.wa * y(info.ia) + info.wb * y(info.ib);
         break;
+      case AverageInterp:
+        // average interpolation
+        result = (info.wa * y(info.ia) + info.wb * y(info.ib)) / info.ti;
+        break;
       case NearestInterp:
         // pick closest point
         result = (info.wa > info.wb ? y(info.ia) : y(info.ib));
@@ -150,7 +176,7 @@ double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMe
 
 /// linear interpolation of the function y = f(x) at points xi
 /// assumes that x is strictly increasing
-Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod interpMethod, ExtrapMethod extrapMethod) {
+Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) {
 
   size_t N = x.size();
 
@@ -161,7 +187,7 @@ Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod i
   }
 
   for (unsigned i = 0; i < N; ++i) {
-    result(i) = interp(x, y, xi(i), interpMethod, extrapMethod);
+    result(i) = interp(x, y, xi(i), interpMethod, extrapMethod, ti);
   }
 
   return result;
diff --git a/src/utilities/data/Vector.hpp b/src/utilities/data/Vector.hpp
index 7c61a925a87..f1b1ebd7e02 100644
--- a/src/utilities/data/Vector.hpp
+++ b/src/utilities/data/Vector.hpp
@@ -59,7 +59,8 @@ enum InterpMethod
   LinearInterp,
   NearestInterp,
   HoldLastInterp,
-  HoldNextInterp
+  HoldNextInterp,
+  AverageInterp
 };
 
 /** Enum to specify the extrapolation method. */
@@ -75,21 +76,25 @@ struct UTILITIES_API InterpInfo
   bool extrapolated;  // was point out of range
   unsigned ia, ib;    // indices of two nearest points
   double wa, wb;      // weights of two nearest points
+  double ti;          // length of interval
 };
 
 /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly
- *  increasing. */
-UTILITIES_API InterpInfo interpInfo(const Vector& x, double xi);
+ *  increasing. ti is the total seconds of the timestep interval; it is used for
+ *  AverageInterp and must be positive. */
+UTILITIES_API InterpInfo interpInfo(const Vector& x, double xi, double ti);
 
 /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly
- *  increasing */
+ *  increasing. ti is the total seconds of the timestep interval; it is used for
+ *  AverageInterp and must be positive. */
 UTILITIES_API double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMethod = LinearInterp,
-                            ExtrapMethod extrapMethod = NoneExtrap);
+                            ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0);
 
 /** Linear interpolation of the function y = f(x) at points xi. Assumes that x is strictly
- *  increasing. */
+ *  increasing. ti is the total seconds of the timestep interval; it is used for
+ *  AverageInterp and must be positive. */
 UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod interpMethod = LinearInterp,
-                            ExtrapMethod extrapMethod = NoneExtrap);
+                            ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0);
 
 //@}
 /** @name Common Methods and Vector Operations */
diff --git a/src/utilities/data/Vector.i b/src/utilities/data/Vector.i
index ce8606dceee..3e45d9e0d78 100644
--- a/src/utilities/data/Vector.i
+++ b/src/utilities/data/Vector.i
@@ -167,23 +167,24 @@ struct UTILITIES_API InterpInfo{
   bool extrapolated; // was point out of range
   unsigned ia, ib; // indices of two nearest points
   double wa, wb; // weights of two nearest points
+  double ti; // length of interval
 };
 
 /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly
  *  increasing. */
-UTILITIES_API InterpInfo interpInfo(const Vector& x, double xi);
+UTILITIES_API InterpInfo interpInfo(const Vector& x, double xi, double ti);
 
 /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly
  *  increasing */
 UTILITIES_API double interp(const Vector& x, const Vector& y, double xi,
                             InterpMethod interpMethod = LinearInterp,
-                            ExtrapMethod extrapMethod = NoneExtrap);
+                            ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0);
 
 /** Linear interpolation of the function y = f(x) at points xi. Assumes that x is strictly
  *  increasing. */
 UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Vector& xi,
                             InterpMethod interpMethod = LinearInterp,
-                            ExtrapMethod extrapMethod = NoneExtrap);
+                            ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0);
 
 //@}
 /** @name Common Methods and Vector Operations */


Test patch:
diff --git a/src/model/test/ModelMerger_GTest.cpp b/src/model/test/ModelMerger_GTest.cpp
index 294d90af21d..7854e090282 100644
--- a/src/model/test/ModelMerger_GTest.cpp
+++ b/src/model/test/ModelMerger_GTest.cpp
@@ -914,10 +914,10 @@ TEST_F(ModelFixture, ModelMerger_Issue_5153) {
   };
 
   std::vector<Point3d> floorprint2_2{
-    {5,  5, 0},
+    {5, 5, 0},
     {10, 5, 0},
     {10, 0, 0},
-    {5,  0, 0},
+    {5, 0, 0},
   };
 
   // set up model 2
@@ -935,14 +935,13 @@ TEST_F(ModelFixture, ModelMerger_Issue_5153) {
 
   space1_2->matchSurfaces(*space2_2);
 
-  auto testModel = [](const Model& model) { 
-
+  auto testModel = [](const Model& model) {
     unsigned numOutdoorSurfaces = 0;
     unsigned numGroundSurfaces = 0;
     unsigned numAdjacentSurfaces = 0;
     unsigned numOutdoorSubSurfaces = 0;
     unsigned numAdjacentSubSurfaces = 0;
-  
+
     for (const auto& surface : model.getConcreteModelObjects<Surface>()) {
       if (surface.outsideBoundaryCondition() == "Outdoors") {
         ++numOutdoorSurfaces;
diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp
index be5370b9180..c102655304b 100644
--- a/src/model/test/ScheduleDay_GTest.cpp
+++ b/src/model/test/ScheduleDay_GTest.cpp
@@ -10,9 +10,12 @@
 #include "../ScheduleDay_Impl.hpp"
 #include "../ScheduleTypeLimits.hpp"
 #include "../ScheduleTypeLimits_Impl.hpp"
+#include "../Timestep.hpp"
+#include "../Timestep_Impl.hpp"
 
 #include "../../utilities/time/Date.hpp"
 #include "../../utilities/time/Time.hpp"
+#include "../../utilities/data/TimeSeries.hpp"
 
 using namespace openstudio::model;
 using namespace openstudio;
@@ -50,6 +53,7 @@ TEST_F(ModelFixture, Schedule_Day) {
 
   EXPECT_EQ(0.0, daySchedule.getValue(Time(0, -1, 0)));
   EXPECT_EQ(1.0, daySchedule.getValue(Time(0, 0, 0)));
+  EXPECT_EQ(1.0, daySchedule.getValue(Time(0, 0, 1)));
   EXPECT_EQ(1.0, daySchedule.getValue(Time(0, 6, 0)));
   EXPECT_EQ(1.0, daySchedule.getValue(Time(0, 8, 0)));
   EXPECT_EQ(1.0, daySchedule.getValue(Time(0, 9, 0)));
@@ -174,7 +178,7 @@ TEST_F(ModelFixture, Schedule_Day_Interp) {
   double tol = 1e-5;
 
   ScheduleDay daySchedule(model);
-  EXPECT_FALSE(daySchedule.interpolatetoTimestep());
+  EXPECT_EQ("No", daySchedule.interpolatetoTimestep());
   EXPECT_TRUE(daySchedule.isInterpolatetoTimestepDefaulted());
 
   // schedule is 1 until 12:00
@@ -188,17 +192,31 @@ TEST_F(ModelFixture, Schedule_Day_Interp) {
   EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 24, 0)), tol);
   EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 25, 0)), tol);
 
-  daySchedule.setInterpolatetoTimestep(true);
-  EXPECT_TRUE(daySchedule.interpolatetoTimestep());
+  EXPECT_TRUE(daySchedule.setInterpolatetoTimestep("Linear"));
+  EXPECT_EQ("Linear", daySchedule.interpolatetoTimestep());
   EXPECT_FALSE(daySchedule.isInterpolatetoTimestepDefaulted());
 
   EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, -1, 0)), tol);
   EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 0, 0)), tol);
+  EXPECT_NEAR(0.013890, daySchedule.getValue(Time(0, 0, 1)), tol);
   EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 6, 0)), tol);
   EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 12, 0)), tol);
   EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 18, 0)), tol);
   EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 24, 0)), tol);
   EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 25, 0)), tol);
+
+  daySchedule.setInterpolatetoTimestep("Average");
+  EXPECT_EQ("Average", daySchedule.interpolatetoTimestep());
+  EXPECT_FALSE(daySchedule.isInterpolatetoTimestepDefaulted());
+
+  EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, -1, 0)), tol);
+  EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 0, 0)), tol);
+  EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 0, 1)), tol);
+  EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 6, 0)), tol);
+  EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 12, 0)), tol);
+  EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 18, 0)), tol);
+  EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 24, 0)), tol);
+  EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 25, 0)), tol);
 }
 
 TEST_F(ModelFixture, Schedule_Day_Remove) {
@@ -320,3 +338,280 @@ TEST_F(ModelFixture, Schedule_Day_addValue_NaN_Infinity) {
   EXPECT_FALSE(sch_day.addValue(t, std::numeric_limits<double>::infinity()));
   EXPECT_FALSE(sch_day.addValue(t, -std::numeric_limits<double>::infinity()));
 }
+
+TEST_F(ModelFixture, Schedule_Day_timeSeries) {
+  Model model;
+
+  double tol = 1e-5;
+
+  ScheduleDay sch_day(model);
+
+  Time t1("08:05:00");
+  sch_day.addValue(t1, 0.1);
+  Time t2("21:45:00");
+  sch_day.addValue(t2, 1.0);
+
+  Time t0800("08:00:00");
+  EXPECT_NEAR(8.0 / 24.0, t0800.totalDays(), tol);
+  Time t0805("08:05:00");
+  EXPECT_NEAR((8.0 + (5.0 / 60.0)) / 24.0, t0805.totalDays(), tol);
+  Time t0810("08:10:00");
+  EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t0810.totalDays(), tol);
+  Time t0818("08:18:00");
+  EXPECT_NEAR((8.0 + (18.0 / 60.0)) / 24.0, t0818.totalDays(), tol);
+  Time t0820("08:20:00");
+  EXPECT_NEAR((8.0 + (20.0 / 60.0)) / 24.0, t0820.totalDays(), tol);
+  Time t0900("09:00:00");
+  EXPECT_NEAR(9.0 / 24.0, t0900.totalDays(), tol);
+
+  {  // Interpolate to Timestep = No
+    EXPECT_TRUE(sch_day.setInterpolatetoTimestep("No"));
+    EXPECT_EQ("No", sch_day.interpolatetoTimestep());
+
+    auto timestep = model.getUniqueModelObject<Timestep>();
+
+    openstudio::TimeSeries timeSeries;
+    double value;
+
+    EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(1));
+    timeSeries = sch_day.timeSeries();
+    EXPECT_EQ(24 * 1, timeSeries.dateTimes().size());
+    EXPECT_EQ(24 * 1, timeSeries.values().size());
+    value = sch_day.getValue(t0800);
+    EXPECT_NEAR(0.1, value, tol);
+    value = sch_day.getValue(t0805);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0810);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0818);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0820);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0900);
+    EXPECT_NEAR(1.0, value, tol);
+
+    EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4));
+    timeSeries = sch_day.timeSeries();
+    EXPECT_EQ(24 * 4, timeSeries.dateTimes().size());
+    EXPECT_EQ(24 * 4, timeSeries.values().size());
+    value = sch_day.getValue(t0800);
+    EXPECT_NEAR(0.1, value, tol);
+    value = sch_day.getValue(t0805);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0810);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0818);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0820);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0900);
+    EXPECT_NEAR(1.0, value, tol);
+
+    EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6));
+    timeSeries = sch_day.timeSeries();
+    ASSERT_EQ(24 * 6, timeSeries.dateTimes().size());
+    ASSERT_EQ(24 * 6, timeSeries.values().size());
+    value = sch_day.getValue(t0800);
+    EXPECT_NEAR(0.1, value, tol);
+    value = sch_day.getValue(t0805);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0810);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0818);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0820);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0900);
+    EXPECT_NEAR(1.0, value, tol);
+
+    EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10));
+    timeSeries = sch_day.timeSeries();
+    EXPECT_EQ(24 * 10, timeSeries.dateTimes().size());
+    EXPECT_EQ(24 * 10, timeSeries.values().size());
+    value = sch_day.getValue(t0800);
+    EXPECT_NEAR(0.1, value, tol);
+    value = sch_day.getValue(t0805);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0810);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0818);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0820);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0900);
+    EXPECT_NEAR(1.0, value, tol);
+
+    EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(12));
+    timeSeries = sch_day.timeSeries();
+    EXPECT_EQ(24 * 12, timeSeries.dateTimes().size());
+    EXPECT_EQ(24 * 12, timeSeries.values().size());
+    value = sch_day.getValue(t0800);
+    EXPECT_NEAR(0.1, value, tol);
+    value = sch_day.getValue(t0805);
+    EXPECT_NEAR(0.1, value, tol);  // at this timestep, we do return the 0.1
+    value = sch_day.getValue(t0810);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0818);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0820);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0900);
+    EXPECT_NEAR(1.0, value, tol);
+  }
+
+  {  // Interpolate to Timestep = Average
+    EXPECT_TRUE(sch_day.setInterpolatetoTimestep("Average"));
+    EXPECT_EQ("Average", sch_day.interpolatetoTimestep());
+
+    auto timestep = model.getUniqueModelObject<Timestep>();
+
+    openstudio::TimeSeries timeSeries;
+    double value;
+
+    EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(1));
+    timeSeries = sch_day.timeSeries();
+    EXPECT_EQ(24 * 1, timeSeries.dateTimes().size());
+    EXPECT_EQ(24 * 1, timeSeries.values().size());
+    value = sch_day.getValue(t0800);
+    EXPECT_NEAR(0.1, value, tol);
+    value = sch_day.getValue(t0805);
+    EXPECT_NEAR(0.925, value, tol);
+    value = sch_day.getValue(t0810);
+    EXPECT_NEAR(0.925, value, tol);
+    value = sch_day.getValue(t0818);
+    EXPECT_NEAR(0.925, value, tol);
+    value = sch_day.getValue(t0820);
+    EXPECT_NEAR(0.925, value, tol);
+    value = sch_day.getValue(t0900);
+    EXPECT_NEAR(0.925, value, tol);
+
+    EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4));
+    timeSeries = sch_day.timeSeries();
+    EXPECT_EQ(24 * 4, timeSeries.dateTimes().size());
+    EXPECT_EQ(24 * 4, timeSeries.values().size());
+    value = sch_day.getValue(t0800);
+    EXPECT_NEAR(0.1, value, tol);
+    value = sch_day.getValue(t0805);
+    EXPECT_NEAR(0.7, value, tol);
+    value = sch_day.getValue(t0810);
+    EXPECT_NEAR(0.7, value, tol);
+    value = sch_day.getValue(t0818);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0820);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0900);
+    EXPECT_NEAR(1.0, value, tol);
+
+    EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6));
+    timeSeries = sch_day.timeSeries();
+    ASSERT_EQ(24 * 6, timeSeries.dateTimes().size());
+    ASSERT_EQ(24 * 6, timeSeries.values().size());
+    value = sch_day.getValue(t0800);
+    EXPECT_NEAR(0.1, value, tol);
+    value = sch_day.getValue(t0805);
+    EXPECT_NEAR(0.55, value, tol);
+    value = sch_day.getValue(t0810);
+    EXPECT_NEAR(0.55, value, tol);
+    value = sch_day.getValue(t0818);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0820);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0900);
+    EXPECT_NEAR(1.0, value, tol);
+
+    EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10));
+    timeSeries = sch_day.timeSeries();
+    EXPECT_EQ(24 * 10, timeSeries.dateTimes().size());
+    EXPECT_EQ(24 * 10, timeSeries.values().size());
+    value = sch_day.getValue(t0800);
+    EXPECT_NEAR(0.1, value, tol);
+    value = sch_day.getValue(t0805);
+    EXPECT_NEAR(0.25, value, tol);
+    value = sch_day.getValue(t0810);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0818);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0820);
+    EXPECT_NEAR(1.0, value, tol);
+    value = sch_day.getValue(t0900);
+    EXPECT_NEAR(1.0, value, tol);
+  }
+
+  {  // Interpolate to Timestep = Linear
+    EXPECT_TRUE(sch_day.setInterpolatetoTimestep("Linear"));
+    EXPECT_EQ("Linear", sch_day.interpolatetoTimestep());
+
+    auto timestep = model.getUniqueModelObject<Timestep>();
+
+    openstudio::TimeSeries timeSeries;
+    double value;
+
+    EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(1));
+    timeSeries = sch_day.timeSeries();
+    EXPECT_EQ(24 * 1, timeSeries.dateTimes().size());
+    EXPECT_EQ(24 * 1, timeSeries.values().size());
+    value = sch_day.getValue(t0800);
+    EXPECT_NEAR(0.098969, value, tol);
+    value = sch_day.getValue(t0805);
+    EXPECT_NEAR(0.160365, value, tol);
+    value = sch_day.getValue(t0810);
+    EXPECT_NEAR(0.160365, value, tol);
+    value = sch_day.getValue(t0818);
+    EXPECT_NEAR(0.160365, value, tol);
+    value = sch_day.getValue(t0820);
+    EXPECT_NEAR(0.160365, value, tol);
+    value = sch_day.getValue(t0900);
+    EXPECT_NEAR(0.160365, value, tol);
+
+    EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4));
+    timeSeries = sch_day.timeSeries();
+    EXPECT_EQ(24 * 4, timeSeries.dateTimes().size());
+    EXPECT_EQ(24 * 4, timeSeries.values().size());
+    value = sch_day.getValue(t0800);
+    EXPECT_NEAR(0.098969, value, tol);
+    value = sch_day.getValue(t0805);
+    EXPECT_NEAR(0.110975, value, tol);
+    value = sch_day.getValue(t0810);
+    EXPECT_NEAR(0.110975, value, tol);
+    value = sch_day.getValue(t0818);
+    EXPECT_NEAR(0.127439, value, tol);
+    value = sch_day.getValue(t0820);
+    EXPECT_NEAR(0.127439, value, tol);
+    value = sch_day.getValue(t0900);
+    EXPECT_NEAR(0.160365, value, tol);
+
+    EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6));
+    timeSeries = sch_day.timeSeries();
+    ASSERT_EQ(24 * 6, timeSeries.dateTimes().size());
+    ASSERT_EQ(24 * 6, timeSeries.values().size());
+    value = sch_day.getValue(t0800);
+    EXPECT_NEAR(0.098969, value, tol);
+    value = sch_day.getValue(t0805);
+    EXPECT_NEAR(0.105487, value, tol);
+    value = sch_day.getValue(t0810);
+    EXPECT_NEAR(0.105487, value, tol);
+    value = sch_day.getValue(t0818);
+    EXPECT_NEAR(0.116463, value, tol);
+    value = sch_day.getValue(t0820);
+    EXPECT_NEAR(0.116463, value, tol);
+    value = sch_day.getValue(t0900);
+    EXPECT_NEAR(0.160365, value, tol);
+
+    EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10));
+    timeSeries = sch_day.timeSeries();
+    EXPECT_EQ(24 * 10, timeSeries.dateTimes().size());
+    EXPECT_EQ(24 * 10, timeSeries.values().size());
+    value = sch_day.getValue(t0800);
+    EXPECT_NEAR(0.098969, value, tol);
+    value = sch_day.getValue(t0805);
+    EXPECT_NEAR(0.101097, value, tol);
+    value = sch_day.getValue(t0810);
+    EXPECT_NEAR(0.107682, value, tol);
+    value = sch_day.getValue(t0818);
+    EXPECT_NEAR(0.114268, value, tol);
+    value = sch_day.getValue(t0820);
+    EXPECT_NEAR(0.120853, value, tol);
+    value = sch_day.getValue(t0900);
+    EXPECT_NEAR(0.160365, value, tol);
+  }
+}
diff --git a/src/osversion/test/3_8_0/test_vt_ScheduleDay.osm b/src/osversion/test/3_8_0/test_vt_ScheduleDay.osm
new file mode 100644
index 00000000000..c265fde6cda
--- /dev/null
+++ b/src/osversion/test/3_8_0/test_vt_ScheduleDay.osm
@@ -0,0 +1,14 @@
+
+OS:Version,
+  {9d4d2ac6-81f7-466e-be47-92edf03bbde0}, !- Handle
+  3.7.0;                                  !- Version Identifier
+
+OS:Schedule:Day,
+  {b39f42af-eb9f-4079-ad11-5a527a726900}, !- Handle
+  Schedule Day 1,                         !- Name
+  ,                                       !- Schedule Type Limits Name
+  Yes,                                    !- Interpolate to Timestep
+  24,                                     !- Hour 1
+  0,                                      !- Minute 1
+  0;                                      !- Value Until Time 1
+
diff --git a/src/osversion/test/3_8_0/test_vt_ScheduleDay.rb b/src/osversion/test/3_8_0/test_vt_ScheduleDay.rb
new file mode 100644
index 00000000000..9af267e319c
--- /dev/null
+++ b/src/osversion/test/3_8_0/test_vt_ScheduleDay.rb
@@ -0,0 +1,10 @@
+#require '/usr/local/openstudio-3.6.1/Ruby/openstudio'
+
+include OpenStudio::Model
+
+m = Model.new
+
+sch_day = ScheduleDay.new(m)
+sch_day.setInterpolatetoTimestep(true)
+
+m.save('test_vt_ScheduleDay.osm', true)
diff --git a/src/osversion/test/VersionTranslator_GTest.cpp b/src/osversion/test/VersionTranslator_GTest.cpp
index 6d12d3c4439..d7d81842494 100644
--- a/src/osversion/test/VersionTranslator_GTest.cpp
+++ b/src/osversion/test/VersionTranslator_GTest.cpp
@@ -4186,3 +4186,24 @@ TEST_F(OSVersionFixture, update_3_7_0_to_3_8_0_PeopleDefinition) {
   EXPECT_TRUE(def.isEmpty(9));                               // Enable ASHRAE 55 Comfort Warnings
   EXPECT_EQ("EnclosureAveraged", def.getString(10).get());   // Mean Radiant Temperature Calculation Type
 }
+
+TEST_F(OSVersionFixture, update_3_7_0_to_3_8_0_ScheduleDay) {
+  openstudio::path path = resourcesPath() / toPath("osversion/3_8_0/test_vt_ScheduleDay.osm");
+  osversion::VersionTranslator vt;
+  boost::optional<model::Model> model = vt.loadModel(path);
+  ASSERT_TRUE(model) << "Failed to load " << path;
+
+  openstudio::path outPath = resourcesPath() / toPath("osversion/3_8_0/test_vt_ScheduleDay_updated.osm");
+  model->save(outPath, true);
+
+  std::vector<WorkspaceObject> sch_days = model->getObjectsByType("OS:Schedule:Day");
+  ASSERT_EQ(1u, sch_days.size());
+  WorkspaceObject sch_day = sch_days[0];
+
+  EXPECT_EQ("Schedule Day 1", sch_day.getString(1).get());  // Name
+  EXPECT_TRUE(sch_day.isEmpty(2));                          // Schedule Type Limits Name
+  EXPECT_EQ("Average", sch_day.getString(3).get());         // Interpolate to Timestep
+  EXPECT_EQ(24, sch_day.getInt(4).get());                   // Hour 1
+  EXPECT_EQ(0, sch_day.getInt(5).get());                    // Minute 1
+  EXPECT_EQ(0, sch_day.getDouble(6).get());                 // Value Until Time 1
+}