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 Annex60.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 Real timeStampsNewYear[12] = {
    1262304000, 1293840000, 1325376000,
    1356998400, 1388534400, 1420070400,
    1451606400, 1483228800, 1514764800,
    1546300800, 1577836800, 1609459200}
    ;
  
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 == Annex60.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 == Annex60.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 == Annex60.Utilities.Time.Types.ZeroTime.UnixTimeStamp
 then
    timOff :=0;
  
elseif zerTim == Annex60.Utilities.Time.Types.ZeroTime.NY2010
 or 
    zerTim == Annex60.Utilities.Time.Types.ZeroTime.Custom
 and yearRef == 2010
 then
      timOff :=timeStampsNewYear[1];
  
elseif zerTim == Annex60.Utilities.Time.Types.ZeroTime.NY2011
 or 
    zerTim == Annex60.Utilities.Time.Types.ZeroTime.Custom
 and yearRef == 2011
 then
      timOff :=timeStampsNewYear[2];
  
elseif zerTim == Annex60.Utilities.Time.Types.ZeroTime.NY2012
 or 
    zerTim == Annex60.Utilities.Time.Types.ZeroTime.Custom
 and yearRef == 2012
 then
      timOff :=timeStampsNewYear[3];
  
elseif zerTim == Annex60.Utilities.Time.Types.ZeroTime.NY2013
 or 
    zerTim == Annex60.Utilities.Time.Types.ZeroTime.Custom
 and yearRef == 2013
 then
      timOff :=timeStampsNewYear[4];
  
elseif zerTim == Annex60.Utilities.Time.Types.ZeroTime.NY2014
 or 
    zerTim == Annex60.Utilities.Time.Types.ZeroTime.Custom
 and yearRef == 2014
 then
      timOff :=timeStampsNewYear[5];
  
elseif zerTim == Annex60.Utilities.Time.Types.ZeroTime.NY2015
 or 
    zerTim == Annex60.Utilities.Time.Types.ZeroTime.Custom
 and yearRef == 2015
 then
      timOff :=timeStampsNewYear[6];
  
elseif zerTim == Annex60.Utilities.Time.Types.ZeroTime.NY2016
 or 
    zerTim == Annex60.Utilities.Time.Types.ZeroTime.Custom
 and yearRef == 2016
 then
      timOff :=timeStampsNewYear[7];
  
elseif zerTim == Annex60.Utilities.Time.Types.ZeroTime.NY2017
 or 
    zerTim == Annex60.Utilities.Time.Types.ZeroTime.Custom
 and yearRef == 2017
 then
      timOff :=timeStampsNewYear[8];
  
elseif zerTim == Annex60.Utilities.Time.Types.ZeroTime.NY2018
 or 
    zerTim == Annex60.Utilities.Time.Types.ZeroTime.Custom
 and yearRef == 2018
 then
      timOff :=timeStampsNewYear[9];
  
elseif zerTim == Annex60.Utilities.Time.Types.ZeroTime.NY2018
 or 
    zerTim == Annex60.Utilities.Time.Types.ZeroTime.Custom
 and yearRef == 2019
 then
      timOff :=timeStampsNewYear[10];
  
elseif zerTim == Annex60.Utilities.Time.Types.ZeroTime.NY2018
 or 
    zerTim == Annex60.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 == Annex60.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 == Annex60.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 == Annex60.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 == Annex60.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.