A BACnet DateTime is a simple SEQUENCE that combines a BACnet.Protocol.BACnetDate and a
BACnet.Protocol.BACnetTime. It is the most common concrete timestamp form used throughout
the protocol (application tag 12 when appearing as a primitive).
Because the two components are independent, a BACnet.Protocol.BACnetDateTime can itself act
as a pattern: any special value present in the embedded BACnet.Protocol.BACnetDate or
BACnet.Protocol.BACnetTime makes the whole value a pattern rather than a specific instant.
BACnet Specification References
- ASN.1 production (Clause 21):
BACnetDateTime ::= SEQUENCE { date Date, -- see Clause 20.2.12 for restrictions time Time -- see Clause 20.2.13 for restrictions } - Encoding: The encoding is simply the concatenation of the encodings of
the two components (Clause 20.2.18 CHOICE / SEQUENCE rules apply when the
value is context-tagged, e.g. inside
BACnet.Protocol.BACnetTimestamp). - Usage contexts:
time_of_device_restart, many "last changed" properties, Event Timestamps (the most commonBACnet.Protocol.BACnetTimestampalternative), schedule exception periods, and COV / event notification timestamps.
The conversion helpers delegate to the respective BACnet.Protocol.BACnetDate /
BACnet.Protocol.BACnetTime functions and therefore inherit all pattern-resolution behaviour.
Examples
Converting to/from Elixir DateTime
iex> dt = %BACnetDateTime{date: %BACnetDate{year: 2025, month: 3, day: 15, weekday: 6}, time: %BACnetTime{hour: 14, minute: 30, second: 0, hundredth: 0}}
iex> {:ok, _elixir_dt} = BACnetDateTime.to_datetime(dt)
iex> BACnetDateTime.from_datetime(~U[2025-03-15 14:30:00Z])
%BACnetDateTime{date: %BACnetDate{year: 2025, month: 3, day: 15, weekday: 6}, time: %BACnetTime{hour: 14, minute: 30, second: 0, hundredth: 0}}Pattern DateTime
iex> pattern = %BACnetDateTime{date: %BACnetDate{year: :unspecified, month: 12, day: 25, weekday: :unspecified}, time: %BACnetTime{hour: 0, minute: 0, second: 0, hundredth: 0}}
iex> BACnetDateTime.specific?(pattern)
falseEdge cases
A DateTime is only specific if both the date and time parts are specific:
iex> mixed = %BACnetDateTime{
...> date: %BACnetDate{year: 2025, month: 4, day: 1, weekday: 2},
...> time: %BACnetTime{hour: :unspecified, minute: 0, second: 0, hundredth: 0}
...> }
iex> BACnetDateTime.specific?(mixed)
falseConversion delegates to the individual date/time helpers (including their reference date fallback behavior).
See Also
Summary
Functions
Compares two BACnet DateTime.
Encodes the given BACnet DateTime into an application tag.
Converts a DateTime to a BACnet DateTime.
Converts a NaiveDateTime to a BACnet DateTime.
Parses a BACnet DateTime from BACnet application tags encoding.
Checks whether the given BACnet DateTime is a specific date-time value (every component is a numeric value).
Converts the BACnet DateTime to a DateTime.
Bang-version of to_datetime/1.
Converts the BACnet DateTime to a NaiveDateTime.
Bang-version of to_naive_datetime/1.
Creates a new BACnet DateTime for the current UTC datetime.
Validates whether the given BACnet datetime is in form valid.
Types
@type t() :: %BACnet.Protocol.BACnetDateTime{ date: BACnet.Protocol.BACnetDate.t(), time: BACnet.Protocol.BACnetTime.t() }
Represents a BACnet DateTime (a SEQUENCE of Date + Time).
The contained date and time may themselves contain special values
(:unspecified, :even, etc.). In that case specific?/1 returns false
and the value is treated as a pattern rather than a concrete instant.
Functions
Compares two BACnet DateTime.
Returns :gt if first datetime is later than the second,
and :lt for vice versa.
If the two datetimes are equal, :eq is returned.
Note that this is achieved by converting to DateTime and then
comparing them.
@spec encode(t(), Keyword.t()) :: {:ok, BACnet.Protocol.ApplicationTags.encoding_list()} | {:error, term()}
Encodes the given BACnet DateTime into an application tag.
For tagged encoding, you'll have to strip this down further using manual efforts.
@spec from_datetime(DateTime.t()) :: t()
Converts a DateTime to a BACnet DateTime.
@spec from_naive_datetime(NaiveDateTime.t()) :: t()
Converts a NaiveDateTime to a BACnet DateTime.
@spec parse(BACnet.Protocol.ApplicationTags.encoding_list()) :: {:ok, {t(), rest :: BACnet.Protocol.ApplicationTags.encoding_list()}} | {:error, term()}
Parses a BACnet DateTime from BACnet application tags encoding.
Checks whether the given BACnet DateTime is a specific date-time value (every component is a numeric value).
@spec to_datetime(t(), Calendar.time_zone(), Calendar.time_zone_database()) :: {:ok, DateTime.t()} | {:error, term()}
Converts the BACnet DateTime to a DateTime.
@spec to_datetime!(t(), Calendar.time_zone(), Calendar.time_zone_database()) :: DateTime.t() | no_return()
Bang-version of to_datetime/1.
@spec to_naive_datetime(t()) :: {:ok, NaiveDateTime.t()} | {:error, term()}
Converts the BACnet DateTime to a NaiveDateTime.
@spec to_naive_datetime!(t()) :: NaiveDateTime.t() | no_return()
Bang-version of to_naive_datetime/1.
@spec utc_now() :: t()
Creates a new BACnet DateTime for the current UTC datetime.
Validates whether the given BACnet datetime is in form valid.
It only validates the struct is valid as per type specification.