diff --git a/src/main/java/com/thealgorithms/conversions/TimeConverter.java b/src/main/java/com/thealgorithms/conversions/TimeConverter.java
new file mode 100644
index 000000000000..41cae37d7ad1
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/TimeConverter.java
@@ -0,0 +1,97 @@
+package com.thealgorithms.conversions;
+
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * A utility class to convert between different units of time.
+ *
+ *
This class supports conversions between the following units:
+ *
+ * - seconds
+ * - minutes
+ * - hours
+ * - days
+ * - weeks
+ * - months (approximated as 30.44 days)
+ * - years (approximated as 365.25 days)
+ *
+ *
+ * The conversion is based on predefined constants in seconds.
+ * Results are rounded to three decimal places for consistency.
+ *
+ *
This class is final and cannot be instantiated.
+ *
+ * @see Wikipedia: Unit of time
+ */
+public final class TimeConverter {
+
+ private TimeConverter() {
+ // Prevent instantiation
+ }
+
+ /**
+ * Supported time units with their equivalent in seconds.
+ */
+ private enum TimeUnit {
+ SECONDS(1.0),
+ MINUTES(60.0),
+ HOURS(3600.0),
+ DAYS(86400.0),
+ WEEKS(604800.0),
+ MONTHS(2629800.0), // 30.44 days
+ YEARS(31557600.0); // 365.25 days
+
+ private final double seconds;
+
+ TimeUnit(double seconds) {
+ this.seconds = seconds;
+ }
+
+ public double toSeconds(double value) {
+ return value * seconds;
+ }
+
+ public double fromSeconds(double secondsValue) {
+ return secondsValue / seconds;
+ }
+ }
+
+ private static final Map UNIT_LOOKUP
+ = Map.ofEntries(Map.entry("seconds", TimeUnit.SECONDS), Map.entry("minutes", TimeUnit.MINUTES), Map.entry("hours", TimeUnit.HOURS), Map.entry("days", TimeUnit.DAYS), Map.entry("weeks", TimeUnit.WEEKS), Map.entry("months", TimeUnit.MONTHS), Map.entry("years", TimeUnit.YEARS));
+
+ /**
+ * Converts a time value from one unit to another.
+ *
+ * @param timeValue the numeric value of time to convert; must be non-negative
+ * @param unitFrom the unit of the input value (e.g., "minutes", "hours")
+ * @param unitTo the unit to convert into (e.g., "seconds", "days")
+ * @return the converted value in the target unit, rounded to three decimals
+ * @throws IllegalArgumentException if {@code timeValue} is negative
+ * @throws IllegalArgumentException if either {@code unitFrom} or {@code unitTo} is not supported
+ */
+ public static double convertTime(double timeValue, String unitFrom, String unitTo) {
+ if (timeValue < 0) {
+ throw new IllegalArgumentException("timeValue must be a non-negative number.");
+ }
+
+ TimeUnit from = resolveUnit(unitFrom);
+ TimeUnit to = resolveUnit(unitTo);
+
+ double secondsValue = from.toSeconds(timeValue);
+ double converted = to.fromSeconds(secondsValue);
+
+ return Math.round(converted * 1000.0) / 1000.0;
+ }
+
+ private static TimeUnit resolveUnit(String unit) {
+ if (unit == null) {
+ throw new IllegalArgumentException("Unit cannot be null.");
+ }
+ TimeUnit resolved = UNIT_LOOKUP.get(unit.toLowerCase(Locale.ROOT));
+ if (resolved == null) {
+ throw new IllegalArgumentException("Invalid unit '" + unit + "'. Supported units are: " + UNIT_LOOKUP.keySet());
+ }
+ return resolved;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/conversions/TimeConverterTest.java b/src/test/java/com/thealgorithms/conversions/TimeConverterTest.java
new file mode 100644
index 000000000000..4e10318d4563
--- /dev/null
+++ b/src/test/java/com/thealgorithms/conversions/TimeConverterTest.java
@@ -0,0 +1,69 @@
+package com.thealgorithms.conversions;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.stream.Stream;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class TimeConverterTest {
+
+ @ParameterizedTest(name = "{0} {1} -> {2} {3}")
+ @CsvSource({"60, seconds, minutes, 1", "120, seconds, minutes, 2", "2, minutes, seconds, 120", "2, hours, minutes, 120", "1, days, hours, 24", "1, weeks, days, 7", "1, months, days, 30.438", "1, years, days, 365.25", "3600, seconds, hours, 1", "86400, seconds, days, 1",
+ "604800, seconds, weeks, 1", "31557600, seconds, years, 1"})
+ void
+ testValidConversions(double value, String from, String to, double expected) {
+ assertEquals(expected, TimeConverter.convertTime(value, from, to));
+ }
+
+ @Test
+ @DisplayName("Zero conversion returns zero")
+ void testZeroValue() {
+ assertEquals(0.0, TimeConverter.convertTime(0, "seconds", "hours"));
+ }
+
+ @Test
+ @DisplayName("Same-unit conversion returns original value")
+ void testSameUnitConversion() {
+ assertEquals(123.456, TimeConverter.convertTime(123.456, "minutes", "minutes"));
+ }
+
+ @Test
+ @DisplayName("Negative value throws exception")
+ void testNegativeValue() {
+ assertThrows(IllegalArgumentException.class, () -> TimeConverter.convertTime(-5, "seconds", "minutes"));
+ }
+
+ @ParameterizedTest
+ @CsvSource({"lightyears, seconds", "minutes, centuries"})
+ void testInvalidUnits(String from, String to) {
+ assertThrows(IllegalArgumentException.class, () -> TimeConverter.convertTime(10, from, to));
+ }
+
+ @Test
+ @DisplayName("Null unit throws exception")
+ void testNullUnit() {
+ assertThrows(IllegalArgumentException.class, () -> TimeConverter.convertTime(10, null, "seconds"));
+
+ assertThrows(IllegalArgumentException.class, () -> TimeConverter.convertTime(10, "minutes", null));
+
+ assertThrows(IllegalArgumentException.class, () -> TimeConverter.convertTime(10, null, null));
+ }
+
+ static Stream roundTripCases() {
+ return Stream.of(org.junit.jupiter.params.provider.Arguments.of(1.0, "hours", "minutes"), org.junit.jupiter.params.provider.Arguments.of(2.5, "days", "hours"), org.junit.jupiter.params.provider.Arguments.of(1000, "seconds", "minutes"));
+ }
+
+ @ParameterizedTest
+ @MethodSource("roundTripCases")
+ @DisplayName("Round-trip conversion returns original value")
+ void testRoundTripConversion(double value, String from, String to) {
+ double converted = TimeConverter.convertTime(value, from, to);
+ double roundTrip = TimeConverter.convertTime(converted, to, from);
+ assertEquals(Math.round(value * 1000.0) / 1000.0, Math.round(roundTrip * 1000.0) / 1000.0, 0.05);
+ }
+}