This package contains models for time.
This blocks computes the unix time stamp, date and time
and the day of the week based on the Modelica
variable time
.
First 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()
.
The implementation only supports date computations from year 2010 up to and including 2020.
Daylight saving and time zones are not supported.
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.
model CalendarTime
extends Modelica.Blocks.Icons.DiscreteBlock;
parameter Buildings.Utilities.Time.Types.ZeroTime zerTim
;
parameter Integer yearRef(min=firstYear, max=lastYear) = 2016
;
parameter Modelica.SIunits.Time offset = 0
;
Modelica.Blocks.Interfaces.RealOutput unixTimeStamp(
final unit="s")
;
discrete Modelica.Blocks.Interfaces.IntegerOutput year ;
discrete Modelica.Blocks.Interfaces.IntegerOutput month ;
Modelica.Blocks.Interfaces.IntegerOutput day(fixed=false) ;
Modelica.Blocks.Interfaces.IntegerOutput hour(fixed=false) ;
Modelica.Blocks.Interfaces.RealOutput minute ;
Modelica.Blocks.Interfaces.IntegerOutput weekDay(fixed=false)
;
protected
final constant Integer firstYear = 2010
;
final constant Integer lastYear = firstYear +
size(timeStampsNewYear,1) - 1;
constant Modelica.SIunits.Time timeStampsNewYear[12] = {
1262304000.0, 1293840000.0, 1325376000.0,
1356998400.0, 1388534400.0, 1420070400.0,
1451606400.0, 1483228800.0, 1514764800.0,
1546300800.0, 1577836800.0, 1609459200.0}
;
constant Boolean isLeapYear[11] = {
false, false, true, false,
false, false, true, false,
false, false, true}
;
final constant Integer dayInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
;
parameter Modelica.SIunits.Time timOff(fixed=false) ;
final constant Integer monthRef(min=1, max=12) = 1 ;
final constant Integer dayRef(min=1, max=31) = 1 ;
Integer daysSinceEpoch(fixed=false) ;
discrete Integer yearIndex ;
discrete Real epochLastMonth
;
final parameter Modelica.SIunits.Time hourSampleStart(fixed=false)
;
final parameter Modelica.SIunits.Time daySampleStart(fixed=false)
;
Boolean hourSampleTrigger ;
Boolean daySampleTrigger ;
Boolean firstHourSampling(fixed=true, start=true)
;
Boolean firstDaySampling(fixed=true, start=true)
;
initial equation
hourSampleStart =
integer(time/3600)*3600;
daySampleStart =
integer(time/(3600*24))*3600*24;
hour =
integer(
floor(
rem(unixTimeStamp,3600*24)/3600));
daysSinceEpoch =
integer(
floor(unixTimeStamp/3600/24));
day =
integer(1+
floor((unixTimeStamp-epochLastMonth)/3600/24));
weekDay =
integer(
rem(4+daysSinceEpoch-1,7)+1);
initial algorithm
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) + ".");
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.");
if zerTim == Buildings.Utilities.Time.Types.ZeroTime.UnixTimeStamp
then
timOff :=0;
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;
assert(false, "No valid ZeroTime could be identified.
This is a bug, please submit a bug report.");
end if;
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;
assert(time + offset + timOff >= timeStampsNewYear[1],
if zerTim == Buildings.Utilities.Time.Types.ZeroTime.UnixTimeStamp
then
"Could 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.");
initial algorithm
year :=0;
for i
in 1:
size(timeStampsNewYear,1)
loop
if unixTimeStamp < timeStampsNewYear[i]
and (
if i == 1
then true
else unixTimeStamp >= timeStampsNewYear[i-1])
then
yearIndex :=i - 1;
year :=firstYear + i - 2;
end if;
end for;
epochLastMonth := timeStampsNewYear[yearIndex];
month:=13;
for i
in 1:12
loop
if (unixTimeStamp-epochLastMonth)/3600/24 <
(
if i==2
and isLeapYear[yearIndex]
then 1 + dayInMonth[i]
else dayInMonth[i])
then
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
unixTimeStamp = time + offset + timOff;
when unixTimeStamp >= timeStampsNewYear[
pre(yearIndex)+1]
then
yearIndex=
pre(yearIndex)+1;
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)));
year =
pre(year) + 1;
end when;
when unixTimeStamp >=
pre(epochLastMonth) +
(
if pre(month)==2
and isLeapYear[yearIndex]
then 1 + dayInMonth[
pre(month)]
else dayInMonth[
pre(month)])*3600*24
then
month =
if pre(month) == 12
then 1
else pre(month) + 1;
epochLastMonth =
pre(epochLastMonth) +
(
if pre(month)==2
and isLeapYear[yearIndex]
then 1 + dayInMonth[
pre(month)]
else dayInMonth[
pre(month)])*3600*24;
end when;
hourSampleTrigger =
sample(hourSampleStart, 3600);
when hourSampleTrigger
then
if pre(firstHourSampling)
then
hour =
integer(
floor(
rem(unixTimeStamp,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(unixTimeStamp/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;
day =
integer(1+
floor((unixTimeStamp-epochLastMonth)/3600/24));
firstDaySampling = false;
end when;
minute = (unixTimeStamp/60-daysSinceEpoch*60*24-hour*60);
end CalendarTime;
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.Clock.