summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBotahamec <botahamec@outlook.com>2022-01-31 10:03:59 -0500
committerBotahamec <botahamec@outlook.com>2022-01-31 10:03:59 -0500
commit81f29c5fd9e9ca7b59fe26c0d647890922c4bde2 (patch)
tree53e7c45380b1134eeccb92a08ef61598f9add43a /src
parent2a057c1197d70d1d9b31a090c28dd7b929fdb6ae (diff)
Implemented default formatting
Diffstat (limited to 'src')
-rw-r--r--src/date.rs14
-rw-r--r--src/datetime.rs14
-rw-r--r--src/time.rs39
-rw-r--r--src/timezone.rs100
4 files changed, 146 insertions, 21 deletions
diff --git a/src/date.rs b/src/date.rs
index ff1805b..49a7642 100644
--- a/src/date.rs
+++ b/src/date.rs
@@ -1,6 +1,7 @@
use crate::{Month, Year};
use core::cmp::Ordering;
+use core::fmt::Display;
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct Date {
@@ -91,3 +92,16 @@ impl Ord for Date {
}
// TODO addition
+
+impl Display for Date {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(
+ f,
+ "{:0width$}-{:02}-{:02}",
+ self.year,
+ self.month as u8,
+ self.day,
+ width = 4 + (self.year() < 0.into()) as usize
+ )
+ }
+}
diff --git a/src/datetime.rs b/src/datetime.rs
index 282a56b..f856e74 100644
--- a/src/datetime.rs
+++ b/src/datetime.rs
@@ -3,7 +3,7 @@ use crate::{
Date, Month, Time, TimeZone, Year,
};
-use core::{cmp::Ordering, hash::Hash};
+use core::{cmp::Ordering, fmt::Display, hash::Hash};
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct NaiveDateTime {
@@ -150,3 +150,15 @@ impl<Tz: TimeZone> Ord for DateTime<Tz> {
}
// TODO addition
+
+impl Display for NaiveDateTime {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "{} {}", self.date, self.time)
+ }
+}
+
+impl<Tz: TimeZone> Display for DateTime<Tz> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "{} {}", self.utc_datetime, self.timezone)
+ }
+}
diff --git a/src/time.rs b/src/time.rs
index e80e532..e0a919c 100644
--- a/src/time.rs
+++ b/src/time.rs
@@ -168,3 +168,42 @@ impl Ord for Time {
}
// TODO addition
+
+impl Display for Time {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ let seconds = self.second as f64 + (self.nanosecond as f64 / 1_000_000_000.0);
+ if self.nanosecond() == 0 {
+ write!(f, "{:02}:{:02}:{:02}", self.hour, self.minute, self.second)
+ } else if self.second < 10 {
+ write!(f, "{:02}:{:02}:0{}", self.hour, self.minute, seconds)
+ } else {
+ write!(f, "{:02}:{:02}:{}", self.hour, self.minute, seconds)
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn display_without_nanos() {
+ let time = unsafe { Time::from_hms_nano_unchecked(0, 0, 1, 0) };
+ let time_str = format!("{time}");
+ assert_eq!(time_str, "00:00:01");
+ }
+
+ #[test]
+ fn display_with_nanos_lt_10() {
+ let time = unsafe { Time::from_hms_nano_unchecked(0, 0, 1, 1_000_000) };
+ let time_str = format!("{time}");
+ assert_eq!(time_str, "00:00:01.001");
+ }
+
+ #[test]
+ fn display_with_nanos_gt_10() {
+ let time = unsafe { Time::from_hms_nano_unchecked(0, 0, 10, 1_000_000) };
+ let time_str = format!("{time}");
+ assert_eq!(time_str, "00:00:10.001");
+ }
+}
diff --git a/src/timezone.rs b/src/timezone.rs
index 5284892..3319b12 100644
--- a/src/timezone.rs
+++ b/src/timezone.rs
@@ -1,13 +1,14 @@
-use crate::NaiveDateTime;
+use crate::{DateTime, NaiveDateTime};
use core::convert::Infallible;
+use core::fmt::Display;
/// A type that can be used to represent a TimeZone
-pub trait TimeZone {
+pub trait TimeZone: Sized + Eq + Display {
/// 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;
+ fn utc_offset(&self, date_time: DateTime<Utc>) -> 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>;
@@ -20,7 +21,7 @@ pub struct Utc;
impl TimeZone for Utc {
type Err = Infallible;
- fn utc_offset(&self, _: NaiveDateTime) -> UtcOffset {
+ fn utc_offset(&self, _: DateTime<Utc>) -> UtcOffset {
UtcOffset::UTC
}
@@ -29,10 +30,16 @@ impl TimeZone for Utc {
}
}
+impl Display for Utc {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "UTC")
+ }
+}
+
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
/// A timezone with a fixed offset from UTC
pub struct UtcOffset {
- offset_seconds: i32,
+ offset_seconds: isize,
}
impl UtcOffset {
@@ -44,12 +51,7 @@ impl UtcOffset {
/// 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 {
+ pub const fn from_seconds(seconds: isize) -> Self {
Self {
offset_seconds: seconds,
}
@@ -58,13 +60,8 @@ impl UtcOffset {
/// 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)
+ pub const fn from_hours(hours: isize) -> Self {
+ Self::from_seconds(hours * 3600)
}
/// The number of hours this timezone is ahead of UTC. THis number is
@@ -75,15 +72,45 @@ impl UtcOffset {
/// 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 {
+ pub const fn seconds_ahead(self) -> isize {
self.offset_seconds
}
}
+impl Display for UtcOffset {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ let hours = self.offset_seconds / 3600;
+ let minutes = ((self.offset_seconds % 3600) / 60).abs();
+ let seconds = (self.offset_seconds % 60).abs();
+ let sign = if self.offset_seconds.is_negative() {
+ '-'
+ } else {
+ '+'
+ };
+
+ if self.offset_seconds == 0 {
+ write!(f, "UTC")
+ } else if self.offset_seconds % 3600 == 0 {
+ write!(f, "UTC{:+}", hours)
+ } else if self.offset_seconds % 60 == 0 {
+ write!(f, "UTC{}{:02}:{:02}", sign, hours.abs(), minutes)
+ } else {
+ write!(
+ f,
+ "UTC{}{:02}:{:02}:{:02}",
+ sign,
+ hours.abs(),
+ minutes,
+ seconds
+ )
+ }
+ }
+}
+
impl TimeZone for UtcOffset {
type Err = Infallible;
- fn utc_offset(&self, _: NaiveDateTime) -> UtcOffset {
+ fn utc_offset(&self, _: DateTime<Utc>) -> UtcOffset {
*self
}
@@ -91,3 +118,36 @@ impl TimeZone for UtcOffset {
Ok(*self)
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn utc_offset_display_no_offset() {
+ let offset = UtcOffset::UTC;
+ let offset_str = offset.to_string();
+ assert_eq!(offset_str, "UTC")
+ }
+
+ #[test]
+ fn utc_offset_display_positive_offset() {
+ let offset = UtcOffset::from_hours(1);
+ let offset_str = offset.to_string();
+ assert_eq!(offset_str, "UTC+1")
+ }
+
+ #[test]
+ fn utc_offset_display_minute_offset() {
+ let offset = UtcOffset::from_seconds(60);
+ let offset_str = offset.to_string();
+ assert_eq!(offset_str, "UTC+00:01")
+ }
+
+ #[test]
+ fn utc_offset_display_second_offset() {
+ let offset = UtcOffset::from_seconds(-32);
+ let offset_str = offset.to_string();
+ assert_eq!(offset_str, "UTC-00:00:32")
+ }
+}