Different semantics

use std::ffi::{CStr, c_char};
use std::time::{SystemTime, SystemTimeError, UNIX_EPOCH};

unsafe extern "C" {
    /// Create a formatted time based on timestamp `t`.
    fn ctime(t: *const libc::time_t) -> *const c_char;
}

fn now_formatted() -> Result<String, SystemTimeError> {
    let now = SystemTime::now().duration_since(UNIX_EPOCH)?;
    let seconds = now.as_secs() as i64;

    // SAFETY: `seconds` is generated by the system clock and will not cause
    // overflow
    let ptr = unsafe { ctime(&seconds) };

    // SAFETY: ctime returns a pointer to a preallocated (non-null) buffer
    let ptr = unsafe { CStr::from_ptr(ptr) };

    // SAFETY: ctime uses valid UTF-8
    let fmt = ptr.to_str().unwrap();

    Ok(fmt.trim_end().to_string())
}

fn main() {
    let t = now_formatted();
    println!("{t:?}");
}

Some constructs that other languages allow cannot be expressed in the Rust language.

The ctime function modifies an internal buffer shared between calls. This cannot be represented as Rust’s lifetimes.

  • 'static does not apply, as the semantics are different
  • 'a does not apply, as the buffer outlives each call