summaryrefslogtreecommitdiff
path: root/src/timezone.rs
blob: 528489227041325887e4bcff2483d5ca94de6c54 (plain)
use crate::NaiveDateTime;
use core::convert::Infallible;

/// A type that can be used to represent a TimeZone
pub trait TimeZone {
	/// The error to return in case of a failure to convert the local time to UTC
	type Err;

	/// Given the time in the UTC timezone, determine the UtcOffset
	fn utc_offset(&self, date_time: NaiveDateTime) -> UtcOffset;

	/// Given the local date and time, figure out the offset from UTC
	fn offset_from_local_time(&self, date_time: NaiveDateTime) -> Result<UtcOffset, Self::Err>;
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
/// The UTC time zone
pub struct Utc;

impl TimeZone for Utc {
	type Err = Infallible;

	fn utc_offset(&self, _: NaiveDateTime) -> UtcOffset {
		UtcOffset::UTC
	}

	fn offset_from_local_time(&self, _: NaiveDateTime) -> Result<UtcOffset, Self::Err> {
		Ok(UtcOffset::UTC)
	}
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
/// A timezone with a fixed offset from UTC
pub struct UtcOffset {
	offset_seconds: i32,
}

impl UtcOffset {
	/// The UTC Timezone, represented as an offset
	pub const UTC: Self = Self { offset_seconds: 0 };

	// TODO validation

	/// Makes a new `UtcOffset` timezone with the given timezone difference.
	/// A positive number is the Eastern hemisphere. A negative number is the
	/// Western hemisphere.
	///
	/// # Safety
	///
	/// A value with an absolute value greater than or equal to 86,400 results
	/// in undefined behavior
	pub const unsafe fn from_seconds_unchecked(seconds: i32) -> Self {
		Self {
			offset_seconds: seconds,
		}
	}

	/// Makes a new `UtcOffset` timezone with the given timezone difference.
	/// A positive number is the Eastern hemisphere. A negative number is the
	/// Western hemisphere.
	///
	/// # Safety
	///
	/// A value with an absolute value greater than or equal to 24 results
	/// in undefined behavior
	pub const unsafe fn from_hours_unchecked(hours: i8) -> Self {
		Self::from_seconds_unchecked(hours as i32 * 3600)
	}

	/// The number of hours this timezone is ahead of UTC. THis number is
	/// negative if the timezone is in the Western hemisphere
	pub fn hours_ahead(self) -> f32 {
		self.offset_seconds as f32 / 3600.0
	}

	/// The number of seconds this timezone is ahead of UTC. This number is
	/// negative if the timezone is in the Western hemisphere
	pub const fn seconds_ahead(self) -> i32 {
		self.offset_seconds
	}
}

impl TimeZone for UtcOffset {
	type Err = Infallible;

	fn utc_offset(&self, _: NaiveDateTime) -> UtcOffset {
		*self
	}

	fn offset_from_local_time(&self, _: NaiveDateTime) -> Result<UtcOffset, Self::Err> {
		Ok(*self)
	}
}