Skip to content

uefi-raw: time feature with conversions to/from OffsetDateTime#1899

Closed
phip1611 wants to merge 4 commits intomainfrom
uefi-raw-time-v2
Closed

uefi-raw: time feature with conversions to/from OffsetDateTime#1899
phip1611 wants to merge 4 commits intomainfrom
uefi-raw-time-v2

Conversation

@phip1611
Copy link
Copy Markdown
Member

@phip1611 phip1611 commented Feb 22, 2026

This PR introduces a new time feature that enables interoperability between our EFI Time struct and the time crate's OffsetDateTime type. The goal is to make it easier to work with standard Rust time types while maintaining the safety and validation guarantees of the Time struct.

The PR only focuses on uefi-raw, uefi follows in a next step.

This replaces #1896 as it is clearly a better strategy to move as much of the time handling as possible into a bulletproof crate. I decided to go with time as it is the defacto standard of the ecosystem.

Highlights

  1. New conversions

    • Time::to_offset_date_time() -> converts a valid Time into an OffsetDateTime in UTC or using a provided default local timezone.
    • Time::to_offset_date_time_with_default_timezone(local: UtcOffset) -> handles UNSPECIFIED_TIMEZONE safely with an optional local offset.
    • TryFrom<OffsetDateTime> for Time -> allows converting standard Rust times into EFI Time, with proper error handling for unrepresentable years or offsets with non-zero seconds.
  2. Error handling

    • Introduced ToOffsetDateTimeError and FromOffsetDateTimeError for detailed conversion errors.
    • Covers invalid years, invalid components, unspecified timezone in no_std, and offsets with seconds.
  3. Comprehensive unit tests

    • Tests for all public methods, including boundary cases (nanoseconds, offsets, years).
    • Conversion round-trips validated where possible.
    • I used an LLM (ChatGPT) as sparring partner - very helpful!

Benefits

Checklist

  • Sensible git history (for example, squash "typo" or "fix" commits). See the Rewriting History guide for help.
  • Update the changelog (if necessary)

@phip1611 phip1611 self-assigned this Feb 22, 2026
@phip1611 phip1611 mentioned this pull request Feb 22, 2026
2 tasks
@phip1611 phip1611 requested a review from Copilot February 22, 2026 11:16
@phip1611 phip1611 changed the title uefi-raw: time feature with conversions to/from OffsetDateTime time feature with conversions to/from OffsetDateTime Feb 22, 2026

This comment was marked as outdated.

@phip1611 phip1611 force-pushed the uefi-raw-time-v2 branch 2 times, most recently from 53f2bbd to 3b96089 Compare February 22, 2026 12:41
@phip1611 phip1611 changed the title time feature with conversions to/from OffsetDateTime uefi-raw: time feature with conversions to/from OffsetDateTime Feb 22, 2026
@phip1611 phip1611 force-pushed the uefi-raw-time-v2 branch 2 times, most recently from ba4f75b to 730cd38 Compare February 22, 2026 12:48
By adding a convenient integration with `OffsetDateTime` of the `time`
crate, we make `Time` much more usable. This commit adds the helpers
`to_offset_date_time()` and
`to_offset_date_time_with_default_timezone()`: the latter helps to
better cope with Time::UNSPECIFIED_TIMEZONE.
This helps to better keep an overview.
Comment thread uefi-raw/src/time.rs

//! Date and time types.

use bitflags::bitflags;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hint: this looks quite invasive in github UI. I just moved everything feature( = "time") related into mod time_crate_integration

Comment thread uefi-raw/src/time.rs Outdated
/// Indicates the time should be interpreted as local time.
pub const UNSPECIFIED_TIMEZONE: i16 = 0x07ff;

#[cfg(feature = "time")]
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hint: this looks quite invasive in github UI. I just moved everything feature( = "time") related into mod time_crate_integration

Comment thread uefi-raw/src/time.rs Outdated
}

#[cfg(feature = "time")]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hint: this looks quite invasive in github UI. I just moved everything feature( = "time") related into mod time_crate_integration

Comment thread uefi-raw/src/time.rs
pub struct Daylight: u8 {
/// Daylight information not available or not applicable to the time
/// zone.
const NONE = 0;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bitflags docs recommend against defining a zero flag.

Copy link
Copy Markdown
Member Author

@phip1611 phip1611 Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, that's good to know. How about using newtype_enum!() then?

Comment thread uefi-raw/Cargo.toml

[features]
default = ["time"]
time = ["dep:time"]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A convention I've seen recommended for crates where the major version can be expected to change (which is the case here; I think time is planning on a 1.0 transition at some point), is to include the version in the feature name. Something like time03.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense - thanks

Comment thread uefi-raw/Cargo.toml
uguid.workspace = true

[features]
default = ["time"]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should remove this, uefi-raw should not enable optional deps by default.

Comment thread Cargo.toml
bitflags = "2.0.0"
log = { version = "0.4.5", default-features = false }
ptr_meta = { version = "0.3.0", default-features = false, features = ["derive"] }
time = { version = "0.3", default-features = false, features = [] }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
time = { version = "0.3", default-features = false, features = [] }
time = { version = "0.3", default-features = false }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh good catch, thanks!

Comment thread uefi-raw/src/time.rs
}

#[cfg(feature = "time")]
mod time_crate_integration {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this module (and the tests below) to a separate file? I think that'd be a little easier to read.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, makes sense

Comment thread uefi-raw/src/time.rs
}

impl Time {
fn _to_offset_date_time(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we should avoid underscore-prefixed functions as that turns off unused function warnings. example

Comment thread uefi-raw/src/time.rs
/// let odt: OffsetDateTime = t.to_offset_date_time_with_default_timezone(default_offset).unwrap();
/// assert_eq!(odt.offset(), default_offset);
/// ```
pub fn to_offset_date_time_with_default_timezone(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than providing this, I think we should have a conversion to PrimitiveDateTime. The caller can then choose to convert that to an OffsetDateTime with assume_offset.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh that's a better design. Thanks!

Comment thread uefi-raw/src/time.rs

/// Errors that can happen when converting a [`Time`] to a [`OffsetDateTime`].
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ToOffsetDateTimeError {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced that having detailed error enums is going to be useful to end users, and it potentially makes the API harder to evolve later without a major version bump. The jiff crate for example opted for a mostly-opaque error type: https://docs.rs/jiff/latest/jiff/struct.Error.html.

What do you think about having just one public type like pub struct TimeError(InternalTimeError)? InternalTimeError would not be public, and would be an enum allowing us to provide the detailed error info via Display, but not make it programmatically acessible.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think having a single time error type is fine. thanks for the pointer!

@phip1611
Copy link
Copy Markdown
Member Author

Closing this in favor of a new PR with a new design to keep the discussion clean and focused

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants