Skip to content

Commit 4d0120f

Browse files
authored
Minor clean-ups in DateTime and changelog (#224)
## Description This PR is a follow-up to #223 and cleans up the code a little, adding test assertions and a missing changelog message.
1 parent 437980c commit 4d0120f

2 files changed

Lines changed: 43 additions & 25 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Add `ua::ServerStatusDataType` with `ua::ServerState` and `ua::BuildInfo`.
13+
- Add methods `ua::DateTime::try_from_unix_timestamp_nanos()` and `as_unix_timestamp_nanos()` that
14+
work independently of the `time` feature.
15+
1016
## [0.8.4] - 2025-04-30
1117

1218
### Added
1319

1420
- Add `ua::Guid`.
15-
- Add `ua::EnumDefinition` with `ua::EnumField`.
16-
- Add `ua::ServerStatusDataType` with `ua::ServerState` and `ua::BuildInfo`.
21+
- Add `ua::EnumDefinition` and `ua::EnumField`.
1722

1823
## [0.8.3] - 2025-03-27
1924

src/ua/data_types/date_time.rs

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,62 @@
1-
crate::data_type!(DateTime);
1+
use open62541_sys::{UA_DATETIME_UNIX_EPOCH, UA_DATETIME_USEC};
22

3-
impl DateTime {
4-
/// Returns the UNIX timestamp with nanosecond precision.
5-
#[must_use]
6-
pub fn as_unix_timestamp_nanos(&self) -> i128 {
7-
use open62541_sys::{UA_DATETIME_UNIX_EPOCH, UA_DATETIME_USEC};
3+
use crate::Error;
84

9-
// OPC UA encodes `DateTime` as Windows file time: a 64-bit value that represents the number
10-
// of 100-nanosecond intervals that have elapsed since 12:00 A.M. January 1, 1601 (UTC).
11-
let ua_ticks = i128::from(self.0);
12-
let unix_ticks = ua_ticks - i128::from(UA_DATETIME_UNIX_EPOCH);
13-
unix_ticks * i128::from(1000 / UA_DATETIME_USEC)
14-
}
5+
crate::data_type!(DateTime);
156

7+
impl DateTime {
168
/// Creates [`DateTime`] from a UNIX timestamp with nanosecond precision.
179
///
10+
/// /// # Examples
11+
///
12+
/// ```
13+
/// use open62541::ua;
14+
///
15+
/// // Unix timestamp (1707482096 seconds) corresponding to 9th February 2024, 12:34:56 UTC.
16+
/// let dt = ua::DateTime::try_from_unix_timestamp_nanos(1_707_482_096_000_000_000).unwrap();
17+
///
18+
/// assert_eq!(format!("{dt:?}"), "\"2024-02-09T12:34:56Z\"");
19+
/// ```
20+
///
1821
/// # Errors
1922
///
2023
/// The UNIX timestamp must be valid and in range of the 64-bit representation of [`DateTime`].
21-
pub fn try_from_unix_timestamp_nanos(unix_timestamp_nanos: i128) -> Result<Self, crate::Error> {
22-
use open62541_sys::{UA_DATETIME_UNIX_EPOCH, UA_DATETIME_USEC};
23-
24+
pub fn try_from_unix_timestamp_nanos(unix_timestamp_nanos: i128) -> Result<Self, Error> {
2425
// OPC UA encodes `DateTime` as Windows file time: a 64-bit value that represents the number
2526
// of 100-nanosecond intervals that have elapsed since 12:00 A.M. January 1, 1601 (UTC).
26-
let ticks_unix = unix_timestamp_nanos / i128::from(1000 / UA_DATETIME_USEC);
27-
let ticks_ua = ticks_unix + i128::from(UA_DATETIME_UNIX_EPOCH);
27+
let unix_ticks = unix_timestamp_nanos / i128::from(1000 / UA_DATETIME_USEC);
28+
let ua_ticks = unix_ticks + i128::from(UA_DATETIME_UNIX_EPOCH);
2829

29-
i64::try_from(ticks_ua)
30-
// Explicit module path to avoid linter errors when feature is not enable by `#[cfg()]`.
31-
.map_err(|_| crate::Error::internal("DateTime should be in range"))
30+
i64::try_from(ua_ticks)
31+
.map_err(|_| Error::internal("DateTime should be in range"))
3232
.map(Self)
3333
}
34+
35+
/// Returns the UNIX timestamp with nanosecond precision.
36+
#[must_use]
37+
pub fn as_unix_timestamp_nanos(&self) -> i128 {
38+
// OPC UA encodes `DateTime` as Windows file time: a 64-bit value that represents the number
39+
// of 100-nanosecond intervals that have elapsed since 12:00 A.M. January 1, 1601 (UTC).
40+
let ua_ticks = i128::from(self.0);
41+
let unix_ticks = ua_ticks - i128::from(UA_DATETIME_UNIX_EPOCH);
42+
43+
unix_ticks * i128::from(1000 / UA_DATETIME_USEC)
44+
}
3445
}
3546

3647
#[cfg(feature = "time")]
3748
impl DateTime {
38-
// TODO (breaking change): Return time::UtcDateTime instead of time::OffsetDateTime.
49+
// TODO (breaking change): Return `time::UtcDateTime` instead of `time::OffsetDateTime`.
3950
#[must_use]
4051
pub fn to_utc(&self) -> Option<time::OffsetDateTime> {
4152
time::OffsetDateTime::from_unix_timestamp_nanos(self.as_unix_timestamp_nanos()).ok()
4253
}
4354
}
4455

56+
// TODO (breaking change): Upgrade `time` (0.3.38), add conversion from `time::UtcDateTime`.
4557
#[cfg(feature = "time")]
4658
impl TryFrom<time::OffsetDateTime> for DateTime {
47-
// Explicit module path to avoid linter errors when feature is not enable by `#[cfg()]`.
48-
type Error = crate::Error;
59+
type Error = Error;
4960

5061
/// Creates [`DateTime`] from [`time::OffsetDateTime`].
5162
///
@@ -56,6 +67,8 @@ impl TryFrom<time::OffsetDateTime> for DateTime {
5667
/// use time::macros::datetime;
5768
///
5869
/// let dt: ua::DateTime = datetime!(2024-02-09 12:34:56 UTC).try_into().unwrap();
70+
///
71+
/// assert_eq!(format!("{dt:?}"), "\"2024-02-09T12:34:56Z\"");
5972
/// ```
6073
///
6174
/// # Errors

0 commit comments

Comments
 (0)