BACnet.Protocol.BACnetTimestamp (bacstack v0.1.0-dev.1)

Copy Markdown View Source

A BACnet Timestamp is a CHOICE type that can represent three different notions of "when something happened". The most common form is a full BACnet Date and Time. For trend logs that produce very high-frequency samples, a simple sequence number is often used instead because it consumes far less space and avoids the cost of maintaining a real-time clock with sub-second precision. The third form (Time only) is used when only the time of day is significant.

Timestamps appear in Event Timestamps, in Trend Log records, in the Time Of Device Restart property, in logging notifications, and in many of the "last changed" properties throughout the object model. Because the three alternative encodings have very different sizes and precision characteristics, the choice of which form to use is often an important implementation decision that affects both memory usage and the ability of receiving systems to correlate events across devices.

The type is defined so that a recipient can always determine which of the three alternatives is present without any additional context, which makes it safe to forward or store timestamps in generic log buffers and history archives.

BACnet Specification References

  • ASN.1 (Clause 21):
    BACnetTimeStamp ::= CHOICE {
        time            [0] Time,
        sequence-number [1] Unsigned (0..65535),
        dateTime        [2] BACnetDateTime
    }
  • Encoding (20.2.18): When context-tagged the choice is indicated by the context tag number (0 = time-only, 1 = sequence number, 2 = date+time). The contained value uses its normal application or constructed encoding.
  • Usage drivers: Trend Log (high-frequency samples favour sequence numbers), Event Timestamps property (all three forms allowed), time_of_device_restart.

Examples

Sequence number timestamp (common in Trend Logs)

iex> ts = %BACnetTimestamp{type: :sequence_number, sequence_number: 42837, time: nil, datetime: nil}
iex> ts.sequence_number
42837

Full DateTime timestamp

iex> ts = %BACnetTimestamp{
...>   type: :datetime,
...>   sequence_number: nil,
...>   time: nil,
...>   datetime: %BACnetDateTime{
...>     date: %BACnetDate{year: 2025, month: 4, day: 1, weekday: 2},
...>     time: %BACnetTime{hour: 9, minute: 15, second: 0, hundredth: 0}
...>   }
...> }
iex> ts.type
:datetime

Time-only timestamp

iex> ts = %BACnetTimestamp{type: :time, time: %BACnetTime{hour: 17, minute: 0, second: 0, hundredth: 0}, sequence_number: nil, datetime: nil}
iex> ts.type
:time

See Also

Summary

Types

t()

A CHOICE timestamp (see ASN.1 BACnetTimeStamp production in Clause 21).

Functions

Encodes the given BACnet timestamp into an application tag.

Decodes the given application tags encoding into a BACnet timestamp.

Validates whether the given BACnet timestamp is in form valid.

Types

t()

@type t() :: %BACnet.Protocol.BACnetTimestamp{
  datetime: BACnet.Protocol.BACnetDateTime.t() | nil,
  sequence_number: non_neg_integer() | nil,
  time: BACnet.Protocol.BACnetTime.t() | nil,
  type: :time | :sequence_number | :datetime
}

A CHOICE timestamp (see ASN.1 BACnetTimeStamp production in Clause 21).

  • type: :time -> context tag 0, time field present
  • type: :sequence_number -> context tag 1, sequence_number (0..65535)
  • type: :datetime -> context tag 2, datetime field present

The discriminant type tells the encoder which context tag to emit.

Functions

encode(timestamp, opts \\ [])

@spec encode(t(), Keyword.t()) ::
  {:ok, BACnet.Protocol.ApplicationTags.encoding_list()} | {:error, term()}

Encodes the given BACnet timestamp into an application tag.

parse(tags)

Decodes the given application tags encoding into a BACnet timestamp.

Example:

iex> BACnetTimestamp.parse([{:tagged, {0, <<2, 12, 49, 0>>, 4}}])
{:ok,
{%BACnetTimestamp{
  datetime: nil,
  sequence_number: nil,
  time: %BACnetTime{
    hour: 2,
    hundredth: 0,
    minute: 12,
    second: 49
  },
  type: :time
}, []}}

valid?(t)

@spec valid?(t()) :: boolean()

Validates whether the given BACnet timestamp is in form valid.

It only validates the struct is valid as per type specification.