Skip to main content

DosTimestamp

Struct DosTimestamp 

Source
pub struct DosTimestamp {
    pub date: u16,
    pub time: u16,
    pub tenth: u8,
}
Expand description

An instant in the DOS date and time encoding: two sixteen-bit words counting years from 1980 and seconds in units of two, and a companion field of hundredths.

FAT and exFAT both store this, bit for bit, because both inherited it from the same ancestor rather than each choosing it. Where a directory entry puts the two words and what it keeps beside them differ — a FAT entry holds them as separate fields and gives only its creation time a hundredths byte, an exFAT entry packs them into one 32-bit field and adds a zone offset — so each family’s on-disk layer owns that part and this owns the arithmetic underneath it.

The conversion is lossy in three separate ways, and each one is a property of the encoding rather than a choice:

  • Range. Nothing before SECS_MIN or after SECS_MAX fits, because the date word holds seven bits of year.
  • Granularity. The time word’s seconds field counts two-second units. tenth recovers the rest to a hundredth of a second, and a field the format gives no hundredths to is granular to two seconds.
  • Zone. The words carry no zone. Every conversion here is UTC, so an image’s bytes do not depend on where the machine that wrote it thinks it is. A format that records an offset beside the words records it beside them, not in them.

An instant outside the range is reported rather than wrapped: a year that overflowed seven bits would land in the 1980s and look entirely plausible.

use ferrosys::{DosTimestamp, Timestamp};

// 2015-03-14T09:26:53Z. The odd second is what the hundredths field carries, because
// the seconds field counts twos and rounds down.
let stamp = DosTimestamp::encode(Timestamp::from_secs(1_426_325_213)).expect("in range");
assert_eq!(stamp.tenth, 100);
assert_eq!(DosTimestamp::decode(stamp).secs, 1_426_325_213);

// The Unix epoch is thirty-five years too early for the date word.
assert!(DosTimestamp::encode(Timestamp::from_secs(0)).is_none());

Fields§

§date: u16

The date word: years since 1980 in bits 9..16, month 1 to 12 in bits 5..9, and day 1 to 31 in bits 0..5.

§time: u16

The time word: hours in bits 11..16, minutes in bits 5..11, and two-second units in bits 0..5.

§tenth: u8

Hundredths of a second past what time holds, 0 to 199 — the odd second the two-second unit dropped, plus the fraction within it. A field the format gives no hundredths to leaves this zero.

Implementations§

Source§

impl DosTimestamp

Source

pub const SECS_MIN: i64 = 315_532_800

The first instant the encoding represents: 1980-01-01T00:00:00Z, in seconds since the Unix epoch. The date word counts years from 1980, so there is nothing earlier to encode.

Source

pub const SECS_MAX: i64 = 4_354_819_198

The last instant the encoding represents: 2107-12-31T23:59:58Z, in seconds since the Unix epoch. The year field is seven bits wide, reaching 1980 + 127, and the seconds field counts two-second units, so the final odd second is not representable either.

Source

pub const MAX_TENTH: u8 = 199

The largest value tenth holds: 199 hundredths, which is the odd second the two-second unit dropped plus the ninety-nine hundredths within it.

A byte reaches 255, so the top fifty-six values are ones the field cannot mean — is_well_formed is where an image carrying one is judged.

Source

pub fn encode(time: Timestamp) -> Option<Self>

The date, time, and hundredths this encoding records time as, or None where the instant is outside the range the fields reach.

The seconds field counts two-second units and rounds down, so the dropped odd second reappears in tenth rather than moving the instant. A field that has no hundredths therefore records a time up to two seconds early, which is the encoding’s granularity and not a rounding choice.

Source

pub const fn decode(self) -> Timestamp

The instant this date, time, and hundredths describe, UTC.

Every field is taken as it is found. An image may hold a date no calendar has — day 31 of February, month 0, day 0 — and this reports the instant that arithmetic reaches rather than refusing, because a reader’s job is to say what the image holds and is_well_formed is what judges it. A field with no time word passes zero, which is midnight.

Source

pub const fn is_well_formed(self) -> bool

Whether every field holds a value the encoding defines for it.

This is what decode defers: a month of 0, a day of 31 in February, a twenty-fifth hour, a seconds field counting past 58, and a hundredths byte past MAX_TENTH are each a field an image may carry and no encoder produces. A reader hands back the instant the arithmetic reaches; a scan asks this and reports the ones that answer false.

The month lengths are not tabulated. A date the calendar has is one a round trip through the calendar returns unchanged, and one it does not have is one the arithmetic moves — February 31 comes back as March 3, hour 24 as midnight the next day — so the round trip is the whole test.

use ferrosys::DosTimestamp;

// 2015-03-14T09:26:52Z, which the calendar has.
assert!(DosTimestamp { date: 0x4A6E, time: 0x4B5A, tenth: 0 }.is_well_formed());
// Month 0 and day 0, which is what an entry of zero bytes spells.
assert!(!DosTimestamp::default().is_well_formed());
Source

pub const fn represents(time: Timestamp) -> bool

Whether time is an instant this encoding represents.

The final odd second of 2107 is excluded along with everything past it: the seconds field counts two-second units, so there is no encoding for it.

Trait Implementations§

Source§

impl Clone for DosTimestamp

Source§

fn clone(&self) -> DosTimestamp

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for DosTimestamp

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for DosTimestamp

Source§

fn default() -> DosTimestamp

Returns the “default value” for a type. Read more
Source§

impl PartialEq for DosTimestamp

Source§

fn eq(&self, other: &DosTimestamp) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Copy for DosTimestamp

Source§

impl Eq for DosTimestamp

Source§

impl StructuralPartialEq for DosTimestamp

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.