The PlantDay Class

The PlantDay class serves as a very simple example of an interval server. It is similar to the built-in Weekday time interval, with these exceptions:

Because this is a custom interval server, to be used in one locale only, there is no localization code.

PlantDay implements the ITimeIntervals interface.

Globals

Open the code window for the PlantDay class and add these statements:

'PlantDay class
Implements PITimeServer.ITimeInterval

This statement brings all the defined properties and methods of the ITimeInterval interface into this class.

'Constants
Private Const cName = "PlantDay"
Private Const cPluralName = "PlantDays"
Private Const cShortName = "pd"

These constants are the name and abbreviated name of the interval, which the SDK will use in parsing time arithmetic expressions.

Private Const cMemberLo = 1
Private Const cMemberHi = 7

These constants are the lowest and highest ordinal numbers supported by this time interval.

Private Const cDayStart = #6:00:00 AM#
Private Const cWeekStart = vbMonday

This constant defines the start of the plant day and week.

'Member variables
Private mMemnames(cMemberLo To cMemberHi) As String
Private mShortnames(cMemberLo To cMemberHi) As String

These variables will be initialized to hold the long and short member names.

Class Initialization

In class initialization, you must set up the arrays that hold member names and short names.

On the left-hand drop-down of the code window, select Class. On the right-hand drop-down you will find Initialize and Terminate. Select Initialize, and insert the following statements: (VB-supplied code is shown in gray type).

Private Sub Class_Initialize()
Dim i As Integer
  i = cMemberLo
  mMemnames(i) = "Monday"
  mShortnames(i) = "Mon"
  i = i + 1
  mMemnames(i) = "Tuesday"
  mShortnames(i) = "Tue"
  i = i + 1
  mMemnames(i) = "Wednesday"
  mShortnames(i) = "Wed"
  i = i + 1
  mMemnames(i) = "Thursday"
  mShortnames(i) = "Thu"
  i = i + 1
  mMemnames(i) = "Friday"
  mShortnames(i) = "Fri"
  i = i + 1
  mMemnames(i) = "Saturday"
  mShortnames(i) = "Sat"
  i = i + 1
  mMemnames(i) = "Sunday"
  mShortnames(i) = "Sun"
End Sub

No class termination routine is necessary.

Helper Functions

Insert the following subroutine:

Private Sub CheckDate(dt As Date)
  If dt < #1/1/1970# Or CDbl(dt) >= 2958466 Then _
  Err.Raise tseDATEOUTOFRANGE, cName, _
  "Date must be between 1-Jan-1970 and 31-Dec-9999"
End Sub

This routine checks a Date to see if it is in the valid range for the PI SDK. If not, it raises an error. It will be used by each property or method that returns a Date, to validate the result before returning it.

Properties and Methods

As with the Intervals class, Visual Basic supplies the prototype for each of the ITimeInterval properties and methods. Choose ITimeInterval on the code window’s left-hand drop-down. Then, in turn, choose each of the properties and methods on the right-hand drop-down, and insert the following code into them (VB-supplied code in gray):

Name, PluralName, ShortName

Private Property Get ITimeInterval_Name( _
        Optional ByVal LocaleIndependent As Boolean = False) As String
  ITimeInterval_Name = cName
End Property

Private Property Get ITimeInterval_PluralName( _
        Optional ByVal LocaleIndependent As Boolean = False) As String
  ITimeInterval_PluralName = cPluralName
End Property

Private Property Get ITimeInterval_ShortName( _
        Optional ByVal LocaleIndependent As Boolean = False) As String
  ITimeInterval_ShortName = cShortName
End Property

MemberHi, MemberLo

Private Property Get ITimeInterval_MemberHi() As Long
  ITimeInterval_MemberHi = cMemberHi
End Property

Private Property Get ITimeInterval_MemberLo() As Long
  ITimeInterval_MemberLo = cMemberLo
End Property

MemberName, MemberShortName

Private Property Get ITimeInterval_MemberName( _
        ByVal Index As Long, _
        Optional ByVal LocaleIndependent As Boolean = False) As String
  ITimeInterval_MemberName = mMemnames(Index)
End Property

Private Property Get ITimeInterval_MemberShortName( _
        ByVal Index As Long, _
        Optional ByVal LocaleIndependent As Boolean = False) As String
  ITimeInterval_MemberShortName = mShortnames(Index)
End Property

AddIntervals

In general, interval arithmetic should be done in wallclock time (PITime.LocalDate) rather than UTC (PITime.UTCSeconds).

Private Function ITimeInterval_AddIntervals( _
        ByVal pTime As PITimeServer.PITime, _
        ByVal nIntervals As Double) As Date
Dim retval As Date
  retval = pTime.LocalDate + nIntervals
  CheckDate retval
  ITimeInterval_AddIntervals = retval
End Function

Ordinal

Ordinal uses the VB built-in Weekday function to find the weekday number, where the week begins on Monday. Then, if the time of day is earlier than the start of the plant day, Ordinal subtracts one (modulo 7) from the result.

Private Property Get ITimeInterval_Ordinal( _
        ByVal pTime As PITimeServer.PITime, _
        Optional ByVal LocaleIndependent As Boolean = False) As Long
Dim dt As Date
Dim wkday As Integer
  dt = pTime.LocalDate
  wkday = Weekday(dt, cWeekStart)
  If TimeValue(dt) < cDayStart Then
    If wkday = 1 Then
      wkday = 7
    Else
      wkday = wkday - 1
    End If
  End If
  ITimeInterval_Ordinal = wkday
End Property

StartTime

Private Property Get ITimeInterval_StartTime( _
        ByVal pTime As PITimeServer.PITime, _
        Optional ByVal LocaleIndependent As Boolean = False) As Date
Dim dt As Date
Dim DayStart As Date
  dt = pTime.LocalDate
  DayStart = DateValue(dt) + cDayStart
  If dt < DayStart Then
    DayStart = DayStart - 1
  End if
  CheckDate DayStart
  ITimeInterval_StartTime = DayStart
End Property

FindMember

FindMember needs to do several things:

  1. Decode the index passed in by the caller, which might be a number or a string. If a string, it is looked up, case-insensitively, in the mMemnames and mShortnames arrays. The result will be the ordinal number of the desired day.
  2. Get the ordinal of the “current” day (passed-in pTime argument) and determine the distance to the desired day. E.g. if pTime is Thursday and the caller wants to find Monday, the difference is minus 3.
  3. Decode WhatToFind to see if the caller requires a date in the past or the future. Adjust the difference by a week either direction, if necessary, to fit.
  4. Calculate and return the start time of the desired plant day.
Private Function ITimeInterval_FindMember( _
        ByVal Time As PITimeServer.PITime, _
        ByVal Index As Variant, _
        Optional ByVal WhatToFind As _
        PITimeServer.FindIntervalConstants = 1&, _
        Optional ByVal LocaleIndependent As Boolean = False) As Date
Dim dt As Date        'start of the base interval
Dim ord As Integer    'ordinal of the base interval
Dim retval As Date    'return value
Dim iix As Integer    'integer index of desired interval
Dim uindex As String  'uppercase index string
Dim delta As Integer  'number of days difference from base

  dt = ITimeInterval_StartTime(pTime)
  ord = ITimeInterval_Ordinal(pTime)
  If IsNumeric(Index) Then 'index is an ordinal number
    If Index < cMemberLo Or Index > cMemberHi Then
      Err.Raise 5, cName, "Index out of range"
    End If
    iix = Index
  Else      'index is a name or short name
    uindex = UCase(Index) 'case-insensitive compare
    For iix = cMemberLo To cMemberHi
      If uindex = UCase(mMemnames(iix)) Then Exit For
      If uindex = UCase(mShortnames(iix)) Then Exit For
      If iix = cMemberHi Then _
        Err.Raise tseMEMBERNOTFOUND, cName, _
          "There is no plant day named """ _
          & Index & """"
    Next
  End If

'calculate distance to desired day

  delta = iix - ord

  Select Case WhatToFind   'adjust delta as required

  Case fiBefore
    If delta >= 0 Then delta = delta - 7  'previous week

  Case fiOnOrBefore
    If delta > 0 Then delta = delta - 7   'previous week

  Case fiAfter
    If delta <= 0 Then delta = delta + 7  'following week

  Case fiOnOrAfter
    If delta < 0 Then delta = delta + 7   'following week

  Case fiCurrent
    'current week, do nothing in this case

  End Select

'calculate start time of target day

  retval = dt + delta
  CheckDate retval

  ITimeInterval_FindMember = retval

End Function

Save Your Project

Next
Enabling Operational Intelligence