Buildings.Utilities.Time

Package with models for time

Information

This package contains models for time.

Extends from Modelica.Icons.Package (Icon for standard packages).

Package Content

Name Description
Buildings.Utilities.Time.CalendarTime CalendarTime Computes the unix time stamp and calendar time from the simulation time
Buildings.Utilities.Time.ModelTime ModelTime Model time
Buildings.Utilities.Time.Types Types Package with type definitions
Buildings.Utilities.Time.Examples Examples Collection of models that illustrate model use and test models
Buildings.Utilities.Time.Validation Validation Collection of models that validate the time models

Buildings.Utilities.Time.CalendarTime Buildings.Utilities.Time.CalendarTime

Computes the unix time stamp and calendar time from the simulation time

Buildings.Utilities.Time.CalendarTime

Information

This blocks computes the unix time stamp, date and time and the day of the week based on the Modelica variable time. As for the weather data reader Buildings.BoundaryConditions.WeatherData.ReaderTMY3, time=0 corresponds to January 1st at midnight in the local time zone. The computed outputs are thus also for the local time zone. The year for which time=0 is determined by the parameter zerTim.

Main equations

The unix time stamp corresponding to the current time is computed. From this variables the corresponding, year, date and time are computed using functions such as floor() and ceil().

Assumption and limitations

The implementation only supports date computations from year 2010 up to and including 2020. Daylight saving is not supported.

Typical use and important parameters

The user must define which time and date correspond to time = 0 using the model parameters zerTim, and, if zerTim==Buildings.Utilities.Time.Types.ZeroTime.Custom, the parameter yearRef. When zerTim==Buildings.Utilities.Time.Types.ZeroTime.UnixTimeStampGMT, time is defined with respect to GMT. This is different from the use of time in the weather data reader Buildings.BoundaryConditions.WeatherData.ReaderTMY3, as the weather data files used with this reader are generally defined with time being local time. If zerTim==Buildings.Utilities.Time.Types.ZeroTime.UnixTimeStampGMT is used, then the weather data files read by Buildings.BoundaryConditions.WeatherData.ReaderTMY3 must also be defined with GMT as the time stamp. The user can choose from new year, midnight for a number of years: 2010 to 2030 and also 1970. The latter corresponds to a unix stamp of 0. (Note that when choosing the reference time equal to 0 at 1970, the actual simulation time must be within the 2010-2030 range. For instance startTime = 1262304000 corresponds to the simulation starting on the 1st of January 2010 when setting zerTim = ZeroTime.UnixTimeStamp. This is within the 2010-2020 range and is therefore allowed.) The unix time stamp is formally defined as the number of seconds since midnight of new year in 1970 GMT. To output the correct unix time stamp, set outputUnixTimeStamp=true We then require the local time zone timZon (see Buildings.BoundaryConditions.WeatherData.ReaderTMY3) since time uses the local time zone instead of GMT. We always output unixTimeStampLocal, which is a time stamp that uses the local time zone reference instead of GMT.

Implementation

The model was implemented such that no events are being generated for computing the minute of the day. The model also contains an implementation for setting time=0 for any day and month other than January first. This is however not activated in the current model since these options may wrongly give the impression that it changes the time based on which the solar position is computed and TMY3 data are read.

Extends from Modelica.Blocks.Icons.DiscreteBlock (Graphical layout of discrete block component icon).

Parameters

TypeNameDefaultDescription
ZeroTimezerTim Enumeration for choosing how reference time (time = 0) should be defined
IntegeryearRef2016Year when time = 0, used if zerTim=Custom
Unix time stamp
BooleanoutputUnixTimeStampfalse= true, to output the unix time stamp (using GMT reference)
TimetimZon0The local time zone, for computing the unix time stamp only [s]
Advanced
Timeoffset0Offset that is added to 'time', may be used for computing time in different time zones [s]

Connectors

TypeNameDescription
output RealOutputunixTimeStampLocalUnix time stamp at local time [s]
output RealOutputunixTimeStampUnix time stamp [s]
output IntegerOutputyearYear
output IntegerOutputmonthMonth of the year
output IntegerOutputdayDay of the month
output IntegerOutputhourHour of the day
output RealOutputminuteMinute of the hour
output IntegerOutputweekDayInteger output representing week day (monday = 1, sunday = 7)

Modelica definition

model CalendarTime "Computes the unix time stamp and calendar time from the simulation time" extends Modelica.Blocks.Icons.DiscreteBlock; parameter Buildings.Utilities.Time.Types.ZeroTime zerTim "Enumeration for choosing how reference time (time = 0) should be defined"; parameter Integer yearRef(min=firstYear, max=lastYear) = 2016 "Year when time = 0, used if zerTim=Custom"; parameter Boolean outputUnixTimeStamp = false "= true, to output the unix time stamp (using GMT reference)"; parameter Modelica.Units.SI.Time timZon(displayUnit="h") = 0 "The local time zone, for computing the unix time stamp only"; parameter Modelica.Units.SI.Time offset(displayUnit="h") = 0 "Offset that is added to 'time', may be used for computing time in different time zones"; Modelica.Blocks.Interfaces.RealOutput unixTimeStampLocal(final unit="s") "Unix time stamp at local time"; Modelica.Blocks.Interfaces.RealOutput unixTimeStamp(final unit="s") = unixTimeStampLocal - timZon if outputUnixTimeStamp "Unix time stamp"; discrete Modelica.Blocks.Interfaces.IntegerOutput year "Year"; discrete Modelica.Blocks.Interfaces.IntegerOutput month "Month of the year"; Modelica.Blocks.Interfaces.IntegerOutput day(fixed=false) "Day of the month"; Modelica.Blocks.Interfaces.IntegerOutput hour(fixed=false) "Hour of the day"; Modelica.Blocks.Interfaces.RealOutput minute "Minute of the hour"; Modelica.Blocks.Interfaces.IntegerOutput weekDay(fixed=false) "Integer output representing week day (monday = 1, sunday = 7)"; protected final constant Real eps_time(final unit="s") = 1 "Small value for time"; final constant Integer firstYear = 2010 "First year that is supported, i.e. the first year in timeStampsNewYear[:]"; final constant Integer lastYear = firstYear + size(timeStampsNewYear,1) - 1; constant Modelica.Units.SI.Time timeStampsNewYear[22]={1262304000.0, 1293840000.0,1325376000.0,1356998400.0,1388534400.0,1420070400.0, 1451606400.0,1483228800.0,1514764800.0,1546300800.0,1577836800.0, 1609459200.0,1640995200.0,1672531200.0,1704067200.0,1735689600.0, 1767225600.0,1798761600.0,1830297600.0,1861920000.0,1893456000.0, 1924992000.0} "Epoch time stamps for new years day 2010 to 2031"; constant Boolean isLeapYear[21] = { false, false, true, false, false, false, true, false, false, false, true, false, false, false, true, false, false, false, true, false, false} "List of leap years starting from firstYear (2010), up to and including 2030"; final constant Integer dayInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} "Number of days in each month"; parameter Modelica.Units.SI.Time timOff(fixed=false) "Time offset"; // final parameters since the user may wrongly assume that this model shifts the // actual time of the simulation final constant Integer monthRef(min=1, max=12) = 1 "Month when time = 0"; final constant Integer dayRef(min=1, max=31) = 1 "Day when time = 0"; Integer daysSinceEpoch(fixed=false) "Number of days that passed since 1st of January 1970"; discrete Integer yearIndex "Index of the current year in timeStampsNewYear"; discrete Real epochLastMonth "Unix time stamp of the beginning of the current month"; final parameter Modelica.Units.SI.Time hourSampleStart(fixed=false) "Time when the sampling every hour starts"; final parameter Modelica.Units.SI.Time daySampleStart(fixed=false) "Time when the sampling every day starts"; Boolean hourSampleTrigger "True, if hourly sample time instant"; Boolean daySampleTrigger "True, if daily sample time instant"; Boolean firstHourSampling(fixed=true, start=true) "=true if the hour is sampled the first time"; Boolean firstDaySampling(fixed=true, start=true) "=true if the day is sampled the first time"; initial equation hourSampleStart = integer(time/3600)*3600 - offset; daySampleStart = integer(time/(3600*24))*3600*24 - offset; hour = integer(floor(rem(unixTimeStampLocal,3600*24)/3600)); daysSinceEpoch = integer(floor(unixTimeStampLocal/3600/24)); day = integer(1+floor((unixTimeStampLocal-epochLastMonth)/3600/24)); weekDay = integer(rem(4+daysSinceEpoch-1,7)+1); initial algorithm // check if yearRef is in the valid range assert(not zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom or yearRef>=firstYear and yearRef<=lastYear, "The value you chose for yearRef (=" + String(yearRef) + ") is outside of the validity range of " + String(firstYear) + " to " + String(lastYear) + "."); // check if the day number exists for the chosen month and year assert(not zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom or dayInMonth[monthRef] + (if monthRef==2 and isLeapYear[yearRef-firstYear + 1] then 1 else 0) >=dayRef, "The day number you chose is larger than the number of days contained by the month you chose."); // compute the offset to be added to time based on the parameters specified by the user if zerTim == Buildings.Utilities.Time.Types.ZeroTime.UnixTimeStamp then timOff :=0; elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.UnixTimeStampGMT then timOff :=timZon; elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2010 or zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2010 then timOff :=timeStampsNewYear[1]; elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2011 or zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2011 then timOff :=timeStampsNewYear[2]; elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2012 or zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2012 then timOff :=timeStampsNewYear[3]; elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2013 or zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2013 then timOff :=timeStampsNewYear[4]; elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2014 or zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2014 then timOff :=timeStampsNewYear[5]; elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2015 or zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2015 then timOff :=timeStampsNewYear[6]; elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2016 or zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2016 then timOff :=timeStampsNewYear[7]; elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2017 or zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2017 then timOff :=timeStampsNewYear[8]; elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2018 or zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2018 then timOff :=timeStampsNewYear[9]; elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2019 or zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2019 then timOff :=timeStampsNewYear[10]; elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2020 or zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2020 then timOff :=timeStampsNewYear[11]; else timOff :=0; // this code should not be reachable assert(false, "No valid ZeroTime could be identified. This is a bug, please submit a bug report."); end if; // add additional offset when using a custom date and time if zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom then timOff :=timOff + ((dayRef - 1) + sum({dayInMonth[i] for i in 1:(monthRef - 1)}) + (if monthRef > 2 and isLeapYear[yearRef - firstYear + 1] then 1 else 0))*3600*24; end if; // input data range checks at initial time assert(time + offset + timOff >= timeStampsNewYear[1], if zerTim == Buildings.Utilities.Time.Types.ZeroTime.UnixTimeStamp then "Could not initialize date in the CalendarTime block. You selected 1970 as the time=0 reference. Therefore the simulation startTime must be at least " + String(timeStampsNewYear[1]) + "." elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom then if yearRef <firstYear then "Could not initialize date in the CalendarTime block. You selected a custom time=0 reference. The minimum value for yearRef is then " + String(firstYear) + " but your value is " + String(yearRef) + "." else "Could not initialize date in the CalendarTime block. You selected a custom time=0 reference. Possibly your startTime is too small." else "Could not initialize date in the CalendarTime block. Possibly your startTime is negative?"); assert(time + offset + timOff < timeStampsNewYear[size(timeStampsNewYear,1)], if zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef >= lastYear then "Could not initialize date in the CalendarTime block. You selected a custom time=0 reference. The maximum value for yearRef is then " + String(lastYear) + " but your value is " + String(yearRef) + "." else "Could not initialize date in the CalendarTime block. Possibly your startTime is too large."); // iterate to find the year at initialization initial algorithm year :=0; for i in 1:size(timeStampsNewYear,1) loop // may be reformulated using break if JModelica fixes bug if unixTimeStampLocal < timeStampsNewYear[i] and (if i == 1 then true else unixTimeStampLocal >= timeStampsNewYear[i-1]) then yearIndex :=i - 1; year :=firstYear + i - 2; end if; end for; // iterate to find the month at initialization epochLastMonth := timeStampsNewYear[yearIndex]; month:=13; for i in 1:12 loop if (unixTimeStampLocal-epochLastMonth)/3600/24 < (if i==2 and isLeapYear[yearIndex] then 1 + dayInMonth[i] else dayInMonth[i]) then // construction below avoids the need of a break, which bugs out JModelica month :=min(i,month); else epochLastMonth :=epochLastMonth + (if i == 2 and isLeapYear[yearIndex] then 1 + dayInMonth[i] else dayInMonth[i])*3600*24; end if; end for; equation // compute unix time step based on found offset unixTimeStampLocal = time + offset + timOff; // compute other variables that can be computed without using when() statements hourSampleTrigger =sample(hourSampleStart, 3600); when hourSampleTrigger then if pre(firstHourSampling) then hour = integer(floor(rem(unixTimeStampLocal,3600*24)/3600)); else hour = if (pre(hour) == 23) then 0 else (pre(hour) + 1); end if; firstHourSampling = false; end when; daySampleTrigger =sample(daySampleStart, 86400); when daySampleTrigger then if pre(firstDaySampling) then daysSinceEpoch = integer(floor(unixTimeStampLocal/3600/24)); weekDay=integer(rem(4+daysSinceEpoch-1,7)+1); else daysSinceEpoch = pre(daysSinceEpoch) + 1; weekDay = if (pre(weekDay) == 7) then 1 else (pre(weekDay) + 1); end if; // update the year when passing the epoch time stamp of the next year if unixTimeStampLocal - timeStampsNewYear[pre(yearIndex)+1] > -eps_time then yearIndex=pre(yearIndex)+1; year = pre(year) + 1; else yearIndex = pre(yearIndex); year = pre(year); end if; assert(yearIndex<=size(timeStampsNewYear,1), "Index out of range for epoch vector: timeStampsNewYear needs to be extended beyond the year " + String(firstYear+size(timeStampsNewYear,1))); // update the month when passing the last day of the current month if unixTimeStampLocal - ( pre(epochLastMonth) + (if pre(month)==2 and isLeapYear[yearIndex] then 1 + dayInMonth[pre(month)] else dayInMonth[pre(month)])*3600*24) > -eps_time then month = if pre(month) == 12 then 1 else pre(month) + 1; // Use floor(0.1 + ...) to avoid floating point errors when accumulating epochLastMonth. epochLastMonth = floor(0.1 + pre(epochLastMonth) + (if pre(month)==2 and isLeapYear[yearIndex] then 1 + dayInMonth[pre(month)] else dayInMonth[pre(month)])*3600*24); else month = pre(month); epochLastMonth = pre(epochLastMonth); end if; day = integer(1+floor((unixTimeStampLocal-epochLastMonth)/3600/24)); firstDaySampling = false; end when; // using Real variables and operations for minutes since otherwise too many events are generated minute = (unixTimeStampLocal/60-daysSinceEpoch*60*24-hour*60); end CalendarTime;

Buildings.Utilities.Time.ModelTime Buildings.Utilities.Time.ModelTime

Model time

Buildings.Utilities.Time.ModelTime

Information

This component outputs the model time, which starts at the value at which the simulation starts. For example, if a simulation starts at t=-1, then this block outputs first t=-1, and its output is advanced at the same rate as the simulation time.

The model is used to allow the simulation to start from any time without having to set the parameters for the clock, as would be necessary for the model Modelica.Blocks.Sources.ContinuousClock.

Extends from Modelica.Blocks.Icons.Block (Basic graphical layout of input/output block).

Connectors

TypeNameDescription
output RealOutputyModel time

Modelica definition

block ModelTime "Model time" extends Modelica.Blocks.Icons.Block; Modelica.Blocks.Interfaces.RealOutput y "Model time"; equation y = time; end ModelTime;