Class DisTime

java.lang.Object
edu.nps.moves.dis7.utilities.DisTime

public class DisTime extends Object

This common shared class provides static code for timestamp configuration and conversion utilities, consistently supporting all active open-dis7-java simulations running together on a localhost. Multiple timestamp configurations are available, but dissimilar forms within a single simulation are considered counterproductive and impractical to manage coherently.

DIS time units are a pain to work with. As specified by the IEEE DIS Protocol specification, DIS time units are defined in a custom manner and set equal to 2^31 - 1 time units per hour. The DIS time is set to the number of time units since the start of the hour. Rollover problems can easily occur.] The timestamp field in the PDU header is four bytes long and is specified to be an unsigned integer value. Within a PDU encoding, the timestamp value is int representing number of 1.675 microseconds as interval past hour. IEEE DIS 1278.1, 6.2.88 Timestamp, 6.2.88.2.3 Scale states "The scale of the time value contained in the most significant 31 bits of the timestamp shall be determined by letting zero represent the start of the hour and letting 231 – 1 represent one time unit before the start of the next hour. The next hour then starts back at zero. This results in each time unit representing exactly 3600/(231) s (approximately 1.67638063 μs)."

Thus simulation applications can use float or double representations for simulation time, but proper encoding of timestamp values must be performed by the opendis library when reading or writing values. TODO: confirm correct exposure of methods properly performs conversions.

Multiple timestamp styles and settings are available.

Absolute time and Relative time are two variations for the official timestamp value in the PDU header. Absolute time indicates that the localhost is synchronized to Coordinated Universal Time (UTC), typically meaning that the local computer system is accurately synchronized with UTC via Network Time Protocol (NTP). Synchronization might also be achieved when a computer has a highly accurate reference clock (such as GPS). The packet timestamps originating from such hosts can be legitimately compared to the timestamp of packets received from other hosts, since they all are referenced to the same universal time. Relative timestamps may require further processing in order to achieve synchronization

Absolute timestamps have their least significant bit (LSB) set to 1, and relative timestamps have their LSB set to 0. The idea in the DIS specification is to get the current time since the top of the hour, divide by 2^31-1, shift left one bit, then set the LSB to either 0 for relative timestamps or 1 for absolute timestamps.

Relative timestamps are indicated when the host does NOT have access to NTP, and hence the system time might not be coordinated with that of other hosts. This means that a host receiving DIS packets from several hosts might have to set up a per-host table to correlate baseline time references before ordering packets, and that the PDU timestamp fields from one host is not directly comparable to the PDU timestamp field from another host. (TODO: such support for correlating unsynchronized clocks is not yet implemented by this library.)

Another difficulty with the DIS standard has serious effects. The nature of shared DIS data is such that the timestamp values roll over once an hour, and simulations must be prepared for that eventuality. In other words, at the top of the hour outgoing PDUs will have a timestamp of 1, then just before the end of the hour the PDUs will have a timestamp of 2^31 - 1, and then they will roll back over to a value of 1. Receiving applications should expect this behavior, and not simply expect a monotonically increasing timestamp field. Two nonstandard timestamp alternatives follow.

Unix time. Note that many applications in the wild have been known to completely ignore the DIS standard and to simply put commonly used Unix time (seconds since 1 January 1970) into the timestamp field.

Year time. The rollover associated with official DIS timestamps don't work all that well in numerous applications, which often expect a monotonically increasing timestamp field. Such unpredictable rollover variations are also incompatible with archival recording or streaming playback of Live-Virtual-Constructive (LVC) behavior streams. To avoid such problems, NPS created a "yearly" timestamp which measures hundredths of a second since the start of the current year. The maximum value for such measurements is 3,153,600,000, which can fit into an unsigned int. One hundredth of a second resolution is accurate enough for most applications, and you typically don't have to worry about rollover, instead getting only a monotonically increasing timestamp value.

TODO we are currently investigating whether IEEE_ABSOLUTE together with epochLvc normalization of time reference is sufficient for LVC simulation. Further work is upgrading DisTime support to use the java.time library. Of note is that DISv8 intends to use a 64-bit timestamp.

TODO: timestamp normalization to an initial reference time. Functionality is needed to define a shared common time origin (epochLvc) and also to precisely adjust stream timestamps when coordinating recorded PDU playback within LVC applications. We think the ability to "start at time 0.0", or normalizing initial time to zero for a recorded PDU stream, is actually a pretty common use case. Implementing such a capability is under active development.

Support for java.time package: see Java Tutorials: Date Time and Java Package java.time.

Don McGregor, Mike Bailey, and Don Brutzman

Author:
DMcG
  • Field Details

  • Constructor Details

    • DisTime

      public DisTime()
      Shared instance. This method is not thread-safe. If you are working in multiple threads, create a new instance for each thread. return singleton instance of DisTime
  • Method Details

    • getTimeFormatter

      public static DateTimeFormatter getTimeFormatter()
      Get time format used for text logging
      Returns:
      current timeFormatter
    • setTimeFormatter

      public static void setTimeFormatter(DisTime.TimeFormatterType timeFormatterChoice)
      Set time format for text logging
      Parameters:
      timeFormatterChoice - enumeration for the new timeFormatter to set
    • buildTimeMetadataCommentPdu

      public static CommentPdu buildTimeMetadataCommentPdu()
      Provide parse able time metadata encapsulated in CommentPdu for sharing. TODO: move this to PduFactory
      Returns:
      PDU of interest
    • configureTimeMetadata

      public static boolean configureTimeMetadata(CommentPdu timeMetadataCommentPdu)
      Provide corresponding utility method to parse time metadata from CommentPdu
      Parameters:
      timeMetadataCommentPdu - CommentPdu to parse
      Returns:
      whether parsing and configuration successful
    • getCurrentDisTimestamp

      public static int getCurrentDisTimestamp()
      Recommended form, checks local system clock and returns the current DIS standard relative timestamp based on current timestampStyle.
      Returns:
      DIS time units, relative
      See Also:
    • convertToInstant

      public static Instant convertToInstant(long timestamp)
      Convert timestamp value to Instant for time operations. TODO take into account epochLvc and TimeStampStyle (DIS absolute/relative, Unix or Year). TODO consider different formats for different timestampStyle values.
      Parameters:
      timestamp - value in seconds
      Returns:
      corresponding Instant value (with 31-bit fidelity)
    • convertToLocalTime

      public static LocalTime convertToLocalTime(long timestamp)
      Convert timestamp value to LocalTime for time operations. TODO take into account epochLvc and TimeStampStyle (DIS absolute/relative, Unix or Year). TODO consider different formats for different timestampStyle values.
      Parameters:
      timestamp - value in seconds
      Returns:
      corresponding Instant value (with 31-bit fidelity)
    • convertToLocalDateTime

      public static LocalDateTime convertToLocalDateTime(long timestamp)
      Convert timestamp value to LocalDateTime for time operations. TODO take into account epochLvc and TimeStampStyle (DIS absolute/relative, Unix or Year). TODO consider different formats for different timestampStyle values.
      Parameters:
      timestamp - value in seconds
      Returns:
      corresponding LocalDateTime value (with 31-bit fidelity)
    • convertToString

      public static String convertToString(int timestamp)
      Convert timestamp value to string for logging and diagnostics, taking into account epochLvc and TimeStampStyle (DIS absolute/relative, Unix or Year). TODO consider different formats for different timestampStyle values.
      Parameters:
      timestamp - value in milliseconds
      Returns:
      string value provided by GregorianCalendar
      See Also:
    • setTimestampStyle

      public static void setTimestampStyle(DisTime.TimestampStyle newTimestampStyle)
      Set which time reference is employed throughout this simulation as timestampStyle: IEEE_ABSOLUTE, IEEE_RELATIVE, UNIX, or YEAR.
      Parameters:
      newTimestampStyle - the timestamp style to set for this PDU
    • getTimestampStyle

      public static DisTime.TimestampStyle getTimestampStyle()
      Retrieve the current timestampStyle.
      Returns:
      the current timestampStyle
    • setHostClockSynchronized

      public static void setHostClockSynchronized(boolean newhostClockSynchronized)
      Declare whether host computer clock is accurately synchronized with UTC using a time standard, such as NTP.
      Parameters:
      newhostClockSynchronized - whether localhost is synchronized to time reference
    • isHostClockSynchronized

      public static boolean isHostClockSynchronized()
      Determine whether host computer clock is accurately synchronized with UTC to a time standard
      Returns:
      whether localhost is synchronized to time reference
    • setEpochLvcNow

      public static void setEpochLvcNow()
      Reset epochLvc using current time for zero-based clock, meaning timestamps are normalized to "time zero" of simulation as initial starting time
    • setEpochLvc

      public static void setEpochLvc(Instant newEpochLvc)
      Set Instant value as epochLvc for zero-based clock, meaning timestamps normalized to 0 at that initial starting time
      Parameters:
      newEpochLvc - Instant corresponding to first PDU in series, considered time zero
    • getEpochLvc

      public static Instant getEpochLvc()
      Get initial timestamp for zero-based clock, meaning all timestamps are measured with respect to given starting time
      Returns:
      whether localhost is synchronized to time reference
    • hasEpochLvc

      public static boolean hasEpochLvc()
      Whether epochLvc is currently applied
      Returns:
      whether epochLvc is active
    • clearEpochLvc

      public static void clearEpochLvc()
      Reset epochLvc so it is no longer active
    • getPduFactory

      public static PduFactory getPduFactory()
      Return the static instance of the PduFactory
      Returns:
      the static instance of the PduFactory
    • main

      public static void main(String[] args)
      Main method for testing.
      Parameters:
      args - [unused] command-line arguments are an array of optional String parameters that are passed from execution environment during invocation
      See Also: