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

/// A type that can be used to represent a TimeZone
pub trait TimeZone {
	type Err;

	fn utc_offset(&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) -> 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) -> Result<UtcOffset, Self::Err> {
		Ok(*self)
	}
}