Skip to content

Commit 324ab51

Browse files
feat: add time unit conversion (#996)
1 parent 47ea8bd commit 324ab51

File tree

3 files changed

+165
-0
lines changed

3 files changed

+165
-0
lines changed

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
* [Order of Magnitude Conversion](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/order_of_magnitude_conversion.rs)
8585
* [RGB-CMYK Conversion](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/rgb_cmyk_conversion.rs)
8686
* [Roman Numerals](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/roman_numerals.rs)
87+
* [Time Units](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/time_units.rs)
8788
* Data Structures
8889
* [AVL Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/avl_tree.rs)
8990
* [B-Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/b_tree.rs)

src/conversions/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ mod octal_to_hexadecimal;
1414
mod order_of_magnitude_conversion;
1515
mod rgb_cmyk_conversion;
1616
mod roman_numerals;
17+
mod time_units;
1718

1819
pub use self::binary_to_decimal::binary_to_decimal;
1920
pub use self::binary_to_hexadecimal::binary_to_hexadecimal;
@@ -33,3 +34,4 @@ pub use self::order_of_magnitude_conversion::{
3334
};
3435
pub use self::rgb_cmyk_conversion::rgb_to_cmyk;
3536
pub use self::roman_numerals::{int_to_roman, roman_to_int};
37+
pub use self::time_units::convert_time;

src/conversions/time_units.rs

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
//! # Time Unit Conversion
2+
//!
3+
//! A unit of time is any particular time interval, used as a standard way of
4+
//! measuring or expressing duration. The base unit of time in the International
5+
//! System of Units (SI), and by extension most of the Western world, is the second,
6+
//! defined as about 9 billion oscillations of the caesium atom.
7+
//!
8+
//! More information: <https://en.wikipedia.org/wiki/Unit_of_time>
9+
10+
/// Supported time units for conversion
11+
#[derive(Debug, Clone, Copy, PartialEq)]
12+
pub enum TimeUnit {
13+
Seconds,
14+
Minutes,
15+
Hours,
16+
Days,
17+
Weeks,
18+
Months,
19+
Years,
20+
}
21+
22+
impl TimeUnit {
23+
/// Returns the value of the time unit in seconds
24+
fn to_seconds(self) -> f64 {
25+
match self {
26+
TimeUnit::Seconds => 1.0,
27+
TimeUnit::Minutes => 60.0,
28+
TimeUnit::Hours => 3600.0,
29+
TimeUnit::Days => 86400.0,
30+
TimeUnit::Weeks => 604800.0,
31+
TimeUnit::Months => 2_629_800.0, // Approximate value
32+
TimeUnit::Years => 31_557_600.0, // Approximate value
33+
}
34+
}
35+
36+
/// Parse a string into a TimeUnit (case-insensitive)
37+
fn from_str(s: &str) -> Result<Self, String> {
38+
match s.to_lowercase().as_str() {
39+
"seconds" => Ok(TimeUnit::Seconds),
40+
"minutes" => Ok(TimeUnit::Minutes),
41+
"hours" => Ok(TimeUnit::Hours),
42+
"days" => Ok(TimeUnit::Days),
43+
"weeks" => Ok(TimeUnit::Weeks),
44+
"months" => Ok(TimeUnit::Months),
45+
"years" => Ok(TimeUnit::Years),
46+
_ => Err(format!(
47+
"Invalid unit {s} is not in seconds, minutes, hours, days, weeks, months, years."
48+
)),
49+
}
50+
}
51+
}
52+
53+
/// Convert time from one unit to another
54+
///
55+
/// # Arguments
56+
///
57+
/// * `time_value` - The time value to convert (must be non-negative)
58+
/// * `unit_from` - The source unit (case-insensitive)
59+
/// * `unit_to` - The target unit (case-insensitive)
60+
///
61+
/// # Returns
62+
///
63+
/// Returns the converted time value rounded to 3 decimal places
64+
///
65+
/// # Errors
66+
///
67+
/// Returns an error if:
68+
/// * `time_value` is negative or not a valid number
69+
/// * `unit_from` or `unit_to` is not a valid time unit
70+
pub fn convert_time(time_value: f64, unit_from: &str, unit_to: &str) -> Result<f64, String> {
71+
// Validate that time_value is non-negative
72+
if time_value < 0.0 || time_value.is_nan() || time_value.is_infinite() {
73+
return Err("'time_value' must be a non-negative number.".to_string());
74+
}
75+
76+
// Parse units
77+
let from_unit = TimeUnit::from_str(unit_from)?;
78+
let to_unit = TimeUnit::from_str(unit_to)?;
79+
80+
// Convert: time_value -> seconds -> target unit
81+
let seconds = time_value * from_unit.to_seconds();
82+
let result = seconds / to_unit.to_seconds();
83+
84+
// Round to 3 decimal places
85+
Ok((result * 1000.0).round() / 1000.0)
86+
}
87+
88+
#[cfg(test)]
89+
mod tests {
90+
use super::*;
91+
92+
#[test]
93+
fn test_seconds_to_hours() {
94+
assert_eq!(convert_time(3600.0, "seconds", "hours").unwrap(), 1.0);
95+
}
96+
97+
#[test]
98+
fn test_case_insensitive() {
99+
assert_eq!(convert_time(3500.0, "Seconds", "Hours").unwrap(), 0.972);
100+
assert_eq!(convert_time(1.0, "DaYs", "hours").unwrap(), 24.0);
101+
assert_eq!(convert_time(120.0, "minutes", "SeCoNdS").unwrap(), 7200.0);
102+
}
103+
104+
#[test]
105+
fn test_weeks_to_days() {
106+
assert_eq!(convert_time(2.0, "WEEKS", "days").unwrap(), 14.0);
107+
}
108+
109+
#[test]
110+
fn test_hours_to_minutes() {
111+
assert_eq!(convert_time(0.5, "hours", "MINUTES").unwrap(), 30.0);
112+
}
113+
114+
#[test]
115+
fn test_days_to_months() {
116+
assert_eq!(convert_time(360.0, "days", "months").unwrap(), 11.828);
117+
}
118+
119+
#[test]
120+
fn test_months_to_years() {
121+
assert_eq!(convert_time(360.0, "months", "years").unwrap(), 30.0);
122+
}
123+
124+
#[test]
125+
fn test_years_to_seconds() {
126+
assert_eq!(convert_time(1.0, "years", "seconds").unwrap(), 31_557_600.0);
127+
}
128+
129+
#[test]
130+
fn test_negative_value() {
131+
let result = convert_time(-3600.0, "seconds", "hours");
132+
assert!(result.is_err());
133+
assert_eq!(
134+
result.unwrap_err(),
135+
"'time_value' must be a non-negative number."
136+
);
137+
}
138+
139+
#[test]
140+
fn test_invalid_from_unit() {
141+
let result = convert_time(1.0, "cool", "century");
142+
assert!(result.is_err());
143+
assert!(result.unwrap_err().contains("Invalid unit cool"));
144+
}
145+
146+
#[test]
147+
fn test_invalid_to_unit() {
148+
let result = convert_time(1.0, "seconds", "hot");
149+
assert!(result.is_err());
150+
assert!(result.unwrap_err().contains("Invalid unit hot"));
151+
}
152+
153+
#[test]
154+
fn test_zero_value() {
155+
assert_eq!(convert_time(0.0, "hours", "minutes").unwrap(), 0.0);
156+
}
157+
158+
#[test]
159+
fn test_same_unit() {
160+
assert_eq!(convert_time(100.0, "seconds", "seconds").unwrap(), 100.0);
161+
}
162+
}

0 commit comments

Comments
 (0)