diff --git a/src/lib.rs b/src/lib.rs
index ebad77c6c57a14eb3f182883b074ed8d2a2fa4f2..a68d27603996a32e400a2ec105089a8f3c1367d0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,3 +5,278 @@ mod bindings {
 // Re-export the generated bindings
 pub use bindings::*;
 pub use mavlink_core as mavlink;
+
+pub mod prelude {
+    pub use crate::Timestamp;
+}
+
+/// Trait to get an optional timestamp from a message.
+/// This is of great help when working with multiple message types that can have
+/// a timestamp but don't share a common interface.
+pub trait Timestamp {
+    /// Get the timestamp of the message, if it has one, or None otherwise.
+    fn timestamp(&self) -> Option<u64>;
+}
+
+#[cfg(feature = "lyra")]
+impl Timestamp for lyra::MavMessage {
+    fn timestamp(&self) -> Option<u64> {
+        use bindings::lyra::MavMessage;
+
+        // NOTE: The following match statement is explicitly written to be
+        // exhaustive (if a new message is added, the compiler will complain)
+        match self {
+            MavMessage::IMU_TM(data) => Some(data.timestamp),
+            MavMessage::ADC_TM(data) => Some(data.timestamp),
+            MavMessage::MAVLINK_STATS_TM(data) => Some(data.timestamp),
+            MavMessage::PRESSURE_TM(data) => Some(data.timestamp),
+            MavMessage::GPS_TM(data) => Some(data.timestamp),
+            MavMessage::TEMP_TM(data) => Some(data.timestamp),
+            MavMessage::ADA_TM(data) => Some(data.timestamp),
+            MavMessage::LOAD_TM(data) => Some(data.timestamp),
+            MavMessage::PING_TC(data) => Some(data.timestamp),
+            MavMessage::VOLTAGE_TM(data) => Some(data.timestamp),
+            MavMessage::RECEIVER_TM(data) => Some(data.timestamp),
+            MavMessage::CURRENT_TM(data) => Some(data.timestamp),
+            MavMessage::TASK_STATS_TM(data) => Some(data.timestamp),
+            MavMessage::MEA_TM(data) => Some(data.timestamp),
+            MavMessage::PAYLOAD_FLIGHT_TM(data) => Some(data.timestamp),
+            MavMessage::PIN_TM(data) => Some(data.timestamp),
+            MavMessage::LOGGER_TM(data) => Some(data.timestamp),
+            MavMessage::ARP_TM(data) => Some(data.timestamp),
+            MavMessage::NAS_TM(data) => Some(data.timestamp),
+            MavMessage::FSM_TM(data) => Some(data.timestamp),
+            MavMessage::GSE_TM(data) => Some(data.timestamp),
+            MavMessage::SYS_TM(data) => Some(data.timestamp),
+            MavMessage::ROCKET_FLIGHT_TM(data) => Some(data.timestamp),
+            MavMessage::ATTITUDE_TM(data) => Some(data.timestamp),
+            MavMessage::SET_SERVO_ANGLE_TC(_) => None,
+            MavMessage::RAW_EVENT_TC(_) => None,
+            MavMessage::SET_ORIENTATION_TC(_) => None,
+            MavMessage::CONRIG_STATE_TC(_) => None,
+            MavMessage::SET_ALGORITHM_TC(_) => None,
+            MavMessage::ROCKET_STATS_TM(_) => None,
+            MavMessage::SERVO_TM_REQUEST_TC(_) => None,
+            MavMessage::SET_STEPPER_STEPS_TC(_) => None,
+            MavMessage::ACK_TM(_) => None,
+            MavMessage::SET_REFERENCE_TEMPERATURE_TC(_) => None,
+            MavMessage::PAYLOAD_STATS_TM(_) => None,
+            MavMessage::COMMAND_TC(_) => None,
+            MavMessage::SERVO_TM(_) => None,
+            MavMessage::SET_ATOMIC_VALVE_TIMING_TC(_) => None,
+            MavMessage::WIGGLE_SERVO_TC(_) => None,
+            MavMessage::SET_TARGET_COORDINATES_TC(_) => None,
+            MavMessage::SENSOR_TM_REQUEST_TC(_) => None,
+            MavMessage::SET_DEPLOYMENT_ALTITUDE_TC(_) => None,
+            MavMessage::NACK_TM(_) => None,
+            MavMessage::RESET_SERVO_TC(_) => None,
+            MavMessage::SET_STEPPER_ANGLE_TC(_) => None,
+            MavMessage::SYSTEM_TM_REQUEST_TC(_) => None,
+            MavMessage::SET_COORDINATES_TC(_) => None,
+            MavMessage::SET_REFERENCE_ALTITUDE_TC(_) => None,
+            MavMessage::SET_IGNITION_TIME_TC(_) => None,
+            MavMessage::SET_ANTENNA_COORDINATES_ARP_TC(_) => None,
+            MavMessage::SET_ROCKET_COORDINATES_ARP_TC(_) => None,
+            MavMessage::MOTOR_TM(_) => None,
+            MavMessage::SENSOR_STATE_TM(_) => None,
+            MavMessage::SET_VALVE_MAXIMUM_APERTURE_TC(_) => None,
+        }
+    }
+}
+
+#[cfg(feature = "gemini")]
+impl Timestamp for gemini::MavMessage {
+    fn timestamp(&self) -> Option<u64> {
+        use bindings::gemini::MavMessage;
+
+        // NOTE: The following match statement is explicitly written to be
+        // exhaustive (if a new message is added, the compiler will complain)
+        match self {
+            MavMessage::IMU_TM(data) => Some(data.timestamp),
+            MavMessage::ADC_TM(data) => Some(data.timestamp),
+            MavMessage::MAVLINK_STATS_TM(data) => Some(data.timestamp),
+            MavMessage::PRESSURE_TM(data) => Some(data.timestamp),
+            MavMessage::GPS_TM(data) => Some(data.timestamp),
+            MavMessage::TEMP_TM(data) => Some(data.timestamp),
+            MavMessage::ADA_TM(data) => Some(data.timestamp),
+            MavMessage::LOAD_TM(data) => Some(data.timestamp),
+            MavMessage::PING_TC(data) => Some(data.timestamp),
+            MavMessage::VOLTAGE_TM(data) => Some(data.timestamp),
+            MavMessage::RECEIVER_TM(data) => Some(data.timestamp),
+            MavMessage::CURRENT_TM(data) => Some(data.timestamp),
+            MavMessage::TASK_STATS_TM(data) => Some(data.timestamp),
+            MavMessage::MEA_TM(data) => Some(data.timestamp),
+            MavMessage::PAYLOAD_FLIGHT_TM(data) => Some(data.timestamp),
+            MavMessage::PIN_TM(data) => Some(data.timestamp),
+            MavMessage::LOGGER_TM(data) => Some(data.timestamp),
+            MavMessage::NAS_TM(data) => Some(data.timestamp),
+            MavMessage::FSM_TM(data) => Some(data.timestamp),
+            MavMessage::GSE_TM(data) => Some(data.timestamp),
+            MavMessage::SYS_TM(data) => Some(data.timestamp),
+            MavMessage::ROCKET_FLIGHT_TM(data) => Some(data.timestamp),
+            MavMessage::ATTITUDE_TM(data) => Some(data.timestamp),
+            MavMessage::WIGGLE_SERVO_TC(_) => None,
+            MavMessage::RAW_EVENT_TC(_) => None,
+            MavMessage::SET_REFERENCE_TEMPERATURE_TC(_) => None,
+            MavMessage::SENSOR_TM_REQUEST_TC(_) => None,
+            MavMessage::SET_ATOMIC_VALVE_TIMING_TC(_) => None,
+            MavMessage::SENSOR_STATE_TM(_) => None,
+            MavMessage::SET_COORDINATES_TC(_) => None,
+            MavMessage::SERVO_TM(_) => None,
+            MavMessage::PAYLOAD_STATS_TM(_) => None,
+            MavMessage::SET_DEPLOYMENT_ALTITUDE_TC(_) => None,
+            MavMessage::CONRIG_STATE_TC(_) => None,
+            MavMessage::SET_REFERENCE_ALTITUDE_TC(_) => None,
+            MavMessage::SYSTEM_TM_REQUEST_TC(_) => None,
+            MavMessage::SET_ORIENTATION_TC(_) => None,
+            MavMessage::COMMAND_TC(_) => None,
+            MavMessage::SERVO_TM_REQUEST_TC(_) => None,
+            MavMessage::SET_VALVE_MAXIMUM_APERTURE_TC(_) => None,
+            MavMessage::MOTOR_TM(_) => None,
+            MavMessage::RESET_SERVO_TC(_) => None,
+            MavMessage::SET_TARGET_COORDINATES_TC(_) => None,
+            MavMessage::SET_ALGORITHM_TC(_) => None,
+            MavMessage::SET_SERVO_ANGLE_TC(_) => None,
+            MavMessage::ROCKET_STATS_TM(_) => None,
+            MavMessage::ACK_TM(_) => None,
+            MavMessage::NACK_TM(_) => None,
+            MavMessage::SET_IGNITION_TIME_TC(_) => None,
+        }
+    }
+}
+
+#[cfg(feature = "pyxis")]
+impl Timestamp for pyxis::MavMessage {
+    fn timestamp(&self) -> Option<u64> {
+        use bindings::pyxis::MavMessage;
+
+        // NOTE: The following match statement is explicitly written to be
+        // exhaustive (if a new message is added, the compiler will complain)
+        match self {
+            MavMessage::LOAD_TM(data) => Some(data.timestamp),
+            MavMessage::ADA_TM(data) => Some(data.timestamp),
+            MavMessage::PRESSURE_TM(data) => Some(data.timestamp),
+            MavMessage::CURRENT_TM(data) => Some(data.timestamp),
+            MavMessage::SYS_TM(data) => Some(data.timestamp),
+            MavMessage::ADC_TM(data) => Some(data.timestamp),
+            MavMessage::MAVLINK_STATS_TM(data) => Some(data.timestamp),
+            MavMessage::ATTITUDE_TM(data) => Some(data.timestamp),
+            MavMessage::IMU_TM(data) => Some(data.timestamp),
+            MavMessage::ROCKET_FLIGHT_TM(data) => Some(data.timestamp),
+            MavMessage::FSM_TM(data) => Some(data.timestamp),
+            MavMessage::PING_TC(data) => Some(data.timestamp),
+            MavMessage::LOGGER_TM(data) => Some(data.timestamp),
+            MavMessage::GPS_TM(data) => Some(data.timestamp),
+            MavMessage::PIN_TM(data) => Some(data.timestamp),
+            MavMessage::PAYLOAD_FLIGHT_TM(data) => Some(data.timestamp),
+            MavMessage::NAS_TM(data) => Some(data.timestamp),
+            MavMessage::VOLTAGE_TM(data) => Some(data.timestamp),
+            MavMessage::TEMP_TM(data) => Some(data.timestamp),
+            MavMessage::RECEIVER_TM(data) => Some(data.timestamp),
+            MavMessage::TASK_STATS_TM(data) => Some(data.timestamp),
+            MavMessage::SET_SERVO_ANGLE_TC(_) => None,
+            MavMessage::SET_COORDINATES_TC(_) => None,
+            MavMessage::SET_TARGET_COORDINATES_TC(_) => None,
+            MavMessage::SET_REFERENCE_TEMPERATURE_TC(_) => None,
+            MavMessage::SET_ALGORITHM_TC(_) => None,
+            MavMessage::COMMAND_TC(_) => None,
+            MavMessage::SET_ORIENTATION_TC(_) => None,
+            MavMessage::SERVO_TM_REQUEST_TC(_) => None,
+            MavMessage::WIGGLE_SERVO_TC(_) => None,
+            MavMessage::SENSOR_STATE_TM(_) => None,
+            MavMessage::RAW_EVENT_TC(_) => None,
+            MavMessage::RESET_SERVO_TC(_) => None,
+            MavMessage::SET_REFERENCE_ALTITUDE_TC(_) => None,
+            MavMessage::SYSTEM_TM_REQUEST_TC(_) => None,
+            MavMessage::ACK_TM(_) => None,
+            MavMessage::SENSOR_TM_REQUEST_TC(_) => None,
+            MavMessage::SERVO_TM(_) => None,
+            MavMessage::PAYLOAD_STATS_TM(_) => None,
+            MavMessage::NACK_TM(_) => None,
+            MavMessage::SET_DEPLOYMENT_ALTITUDE_TC(_) => None,
+            MavMessage::ROCKET_STATS_TM(_) => None,
+        }
+    }
+}
+
+#[cfg(feature = "lynx")]
+impl Timestamp for lynx::MavMessage {
+    fn timestamp(&self) -> Option<u64> {
+        use bindings::lynx::MavMessage;
+
+        // NOTE: The following match statement is explicitly written to be
+        // exhaustive (if a new message is added, the compiler will complain)
+        match self {
+            MavMessage::FMM_TM(data) => Some(data.timestamp),
+            MavMessage::GPS_TM(data) => Some(data.timestamp),
+            MavMessage::TMTC_TM(data) => Some(data.timestamp),
+            MavMessage::TEST_TM(data) => Some(data.timestamp),
+            MavMessage::PIN_OBS_TM(data) => Some(data.timestamp),
+            MavMessage::PING_TC(data) => Some(data.timestamp),
+            MavMessage::HR_TM(data) => Some(data.timestamp),
+            MavMessage::SYS_TM(data) => Some(data.timestamp),
+            MavMessage::LOGGER_TM(data) => Some(data.timestamp),
+            MavMessage::MS5803_TM(data) => Some(data.timestamp),
+            MavMessage::SENSORS_TM(data) => Some(data.timestamp),
+            MavMessage::NAS_TM(data) => Some(data.timestamp),
+            MavMessage::TASK_STATS_TM(data) => Some(data.timestamp),
+            MavMessage::DPL_TM(data) => Some(data.timestamp),
+            MavMessage::ABK_TM(data) => Some(data.timestamp),
+            MavMessage::LIS3MDL_TM(data) => Some(data.timestamp),
+            MavMessage::BMX160_TM(data) => Some(data.timestamp),
+            MavMessage::ADA_TM(data) => Some(data.timestamp),
+            MavMessage::WINDTUNNEL_TM(data) => Some(data.timestamp),
+            MavMessage::ADC_TM(data) => Some(data.timestamp),
+            MavMessage::UPLOAD_SETTING_TC(_) => None,
+            MavMessage::ACK_TM(_) => None,
+            MavMessage::LR_TM(_) => None,
+            MavMessage::SET_REFERENCE_TEMPERATURE_TC(_) => None,
+            MavMessage::SET_REFERENCE_ALTITUDE(_) => None,
+            MavMessage::SET_INITIAL_ORIENTATION_TC(_) => None,
+            MavMessage::SET_AEROBRAKE_ANGLE_TC(_) => None,
+            MavMessage::SET_INITIAL_COORDINATES_TC(_) => None,
+            MavMessage::RAW_EVENT_TC(_) => None,
+            MavMessage::TELEMETRY_REQUEST_TC(_) => None,
+            MavMessage::START_LAUNCH_TC(_) => None,
+            MavMessage::SET_DEPLOYMENT_ALTITUDE_TC(_) => None,
+            MavMessage::NOARG_TC(_) => None,
+            MavMessage::NACK_TM(_) => None,
+        }
+    }
+}
+
+#[cfg(feature = "hermes")]
+impl Timestamp for hermes::MavMessage {
+    fn timestamp(&self) -> Option<u64> {
+        use bindings::hermes::MavMessage;
+
+        // NOTE: The following match statement is explicitly written to be
+        // exhaustive (if a new message is added, the compiler will complain)
+        match self {
+            MavMessage::TMTC_TM(data) => Some(data.timestamp),
+            MavMessage::ADA_TM(data) => Some(data.timestamp),
+            MavMessage::IGN_TM(data) => Some(data.timestamp),
+            MavMessage::FMM_TM(data) => Some(data.timestamp),
+            MavMessage::SM_TM(data) => Some(data.timestamp),
+            MavMessage::PING_TC(data) => Some(data.timestamp),
+            MavMessage::GPS_TM(data) => Some(data.timestamp),
+            MavMessage::TEST_TM(data) => Some(data.timestamp.into()),
+            MavMessage::ADIS_TM(data) => Some(data.timestamp),
+            MavMessage::MPU_TM(data) => Some(data.timestamp),
+            MavMessage::SYS_TM(data) => Some(data.timestamp),
+            MavMessage::ADC_TM(data) => Some(data.timestamp),
+            MavMessage::LOGGER_TM(data) => Some(data.timestamp),
+            MavMessage::DPL_TM(data) => Some(data.timestamp),
+            MavMessage::START_LAUNCH_TC(_) => None,
+            MavMessage::CAN_TM(_) => None,
+            MavMessage::UPLOAD_SETTING_TC(_) => None,
+            MavMessage::NOARG_TC(_) => None,
+            MavMessage::NACK_TM(_) => None,
+            MavMessage::RAW_EVENT_TC(_) => None,
+            MavMessage::ACK_TM(_) => None,
+            MavMessage::HR_TM(_) => None,
+            MavMessage::LR_TM(_) => None,
+            MavMessage::TELEMETRY_REQUEST_TC(_) => None,
+        }
+    }
+}