Skip to content

Commit 9665b4d

Browse files
Added-time-converter-algorithm
1 parent 881dafb commit 9665b4d

2 files changed

Lines changed: 184 additions & 0 deletions

File tree

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package com.thealgorithms.conversions;
2+
3+
import java.util.Locale;
4+
import java.util.Map;
5+
6+
/**
7+
* A utility class to convert between different units of time.
8+
*
9+
* <p>This class supports conversions between the following units:
10+
* <ul>
11+
* <li>seconds</li>
12+
* <li>minutes</li>
13+
* <li>hours</li>
14+
* <li>days</li>
15+
* <li>weeks</li>
16+
* <li>months (approximated as 30.44 days)</li>
17+
* <li>years (approximated as 365.25 days)</li>
18+
* </ul>
19+
*
20+
* <p>The conversion is based on predefined constants in seconds.
21+
* Results are rounded to three decimal places for consistency.
22+
*
23+
* <p>This class is final and cannot be instantiated.
24+
*/
25+
public final class TimeConverter {
26+
27+
private TimeConverter() {
28+
// Prevent instantiation
29+
}
30+
31+
/**
32+
* Supported time units with their equivalent in seconds.
33+
*/
34+
private enum TimeUnit {
35+
SECONDS(1.0),
36+
MINUTES(60.0),
37+
HOURS(3600.0),
38+
DAYS(86400.0),
39+
WEEKS(604800.0),
40+
MONTHS(2629800.0), // 30.44 days
41+
YEARS(31557600.0); // 365.25 days
42+
43+
private final double seconds;
44+
45+
TimeUnit(double seconds) {
46+
this.seconds = seconds;
47+
}
48+
49+
public double toSeconds(double value) {
50+
return value * seconds;
51+
}
52+
53+
public double fromSeconds(double secondsValue) {
54+
return secondsValue / seconds;
55+
}
56+
}
57+
58+
private static final Map<String, TimeUnit> UNIT_LOOKUP =
59+
Map.ofEntries(
60+
Map.entry("seconds", TimeUnit.SECONDS),
61+
Map.entry("minutes", TimeUnit.MINUTES),
62+
Map.entry("hours", TimeUnit.HOURS),
63+
Map.entry("days", TimeUnit.DAYS),
64+
Map.entry("weeks", TimeUnit.WEEKS),
65+
Map.entry("months", TimeUnit.MONTHS),
66+
Map.entry("years", TimeUnit.YEARS));
67+
68+
/**
69+
* Converts a time value from one unit to another.
70+
*
71+
* @param timeValue the numeric value of time to convert; must be non-negative
72+
* @param unitFrom the unit of the input value (e.g., "minutes", "hours")
73+
* @param unitTo the unit to convert into (e.g., "seconds", "days")
74+
* @return the converted value in the target unit, rounded to three decimals
75+
* @throws IllegalArgumentException if {@code timeValue} is negative
76+
* @throws IllegalArgumentException if either {@code unitFrom} or {@code unitTo} is not supported
77+
*/
78+
public static double convertTime(double timeValue, String unitFrom, String unitTo) {
79+
if (timeValue < 0) {
80+
throw new IllegalArgumentException("timeValue must be a non-negative number.");
81+
}
82+
83+
TimeUnit from = resolveUnit(unitFrom);
84+
TimeUnit to = resolveUnit(unitTo);
85+
86+
double secondsValue = from.toSeconds(timeValue);
87+
double converted = to.fromSeconds(secondsValue);
88+
89+
return Math.round(converted * 1000.0) / 1000.0;
90+
}
91+
92+
private static TimeUnit resolveUnit(String unit) {
93+
if (unit == null) {
94+
throw new IllegalArgumentException("Unit cannot be null.");
95+
}
96+
TimeUnit resolved = UNIT_LOOKUP.get(unit.toLowerCase(Locale.ROOT));
97+
if (resolved == null) {
98+
throw new IllegalArgumentException(
99+
"Invalid unit '" + unit + "'. Supported units are: " + UNIT_LOOKUP.keySet());
100+
}
101+
return resolved;
102+
}
103+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.thealgorithms.conversions;
2+
3+
import org.junit.jupiter.api.DisplayName;
4+
import org.junit.jupiter.api.Test;
5+
import org.junit.jupiter.params.ParameterizedTest;
6+
import org.junit.jupiter.params.provider.CsvSource;
7+
import org.junit.jupiter.params.provider.MethodSource;
8+
9+
import java.util.stream.Stream;
10+
11+
import static org.junit.jupiter.api.Assertions.*;
12+
13+
class TimeConverterTest {
14+
15+
@ParameterizedTest(name = "{0} {1} -> {2} {3}")
16+
@CsvSource({
17+
"60, seconds, minutes, 1",
18+
"120, seconds, minutes, 2",
19+
"2, minutes, seconds, 120",
20+
"2, hours, minutes, 120",
21+
"1, days, hours, 24",
22+
"1, weeks, days, 7",
23+
"1, months, days, 30.438",
24+
"1, years, days, 365.25",
25+
"3600, seconds, hours, 1",
26+
"86400, seconds, days, 1",
27+
"604800, seconds, weeks, 1",
28+
"31557600, seconds, years, 1"
29+
})
30+
void testValidConversions(double value, String from, String to, double expected) {
31+
assertEquals(expected, TimeConverter.convertTime(value, from, to));
32+
}
33+
34+
@Test
35+
@DisplayName("Zero conversion returns zero")
36+
void testZeroValue() {
37+
assertEquals(0.0, TimeConverter.convertTime(0, "seconds", "hours"));
38+
}
39+
40+
@Test
41+
@DisplayName("Same-unit conversion returns original value")
42+
void testSameUnitConversion() {
43+
assertEquals(123.456, TimeConverter.convertTime(123.456, "minutes", "minutes"));
44+
}
45+
46+
@Test
47+
@DisplayName("Negative value throws exception")
48+
void testNegativeValue() {
49+
assertThrows(IllegalArgumentException.class, () ->
50+
TimeConverter.convertTime(-5, "seconds", "minutes"));
51+
}
52+
53+
@ParameterizedTest
54+
@CsvSource({
55+
"lightyears, seconds",
56+
"minutes, centuries"
57+
})
58+
void testInvalidUnits(String from, String to) {
59+
assertThrows(IllegalArgumentException.class, () ->
60+
TimeConverter.convertTime(10, from, to));
61+
}
62+
63+
static Stream<org.junit.jupiter.params.provider.Arguments> roundTripCases() {
64+
return Stream.of(
65+
org.junit.jupiter.params.provider.Arguments.of(1.0, "hours", "minutes"),
66+
org.junit.jupiter.params.provider.Arguments.of(2.5, "days", "hours"),
67+
org.junit.jupiter.params.provider.Arguments.of(1000, "seconds", "minutes"));
68+
}
69+
70+
@ParameterizedTest
71+
@MethodSource("roundTripCases")
72+
@DisplayName("Round-trip conversion returns original value")
73+
void testRoundTripConversion(double value, String from, String to) {
74+
double converted = TimeConverter.convertTime(value, from, to);
75+
double roundTrip = TimeConverter.convertTime(converted, to, from);
76+
assertEquals(
77+
Math.round(value * 1000.0) / 1000.0,
78+
Math.round(roundTrip * 1000.0) / 1000.0,
79+
0.05);
80+
}
81+
}

0 commit comments

Comments
 (0)