From 0b1eb35900cb5754e53394eefff9911713845781 Mon Sep 17 00:00:00 2001
From: Viktor Klang <viktor.klang@gmail.com>
Date: Tue, 19 Feb 2013 20:36:08 +0100
Subject: [PATCH 1/4] Adding IDEA specific subdirs to .gitignore

---
 .gitignore | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.gitignore b/.gitignore
index 4007fb21..e47daa7a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,8 @@
 /.project
 /.cache
 /.settings
+.idea
+.idea_modules
 /bin
 /bin-test-lib
 target/

From 796f25acac8ab324885c058e88134b25f31fc8dd Mon Sep 17 00:00:00 2001
From: Viktor Klang <viktor.klang@gmail.com>
Date: Tue, 19 Feb 2013 20:36:46 +0100
Subject: [PATCH 2/4] Deprecating getMilliseconds* and getNanoseconds* and add
 getDuration*

---
 .../main/java/com/typesafe/config/Config.java | 45 ++++++++++++--
 .../typesafe/config/impl/SimpleConfig.java    | 61 +++++++++++--------
 .../com/typesafe/config/impl/ConfigTest.scala | 23 +++++++
 3 files changed, 100 insertions(+), 29 deletions(-)

diff --git a/config/src/main/java/com/typesafe/config/Config.java b/config/src/main/java/com/typesafe/config/Config.java
index 0a72f5b0..47f0e728 100644
--- a/config/src/main/java/com/typesafe/config/Config.java
+++ b/config/src/main/java/com/typesafe/config/Config.java
@@ -6,6 +6,7 @@ package com.typesafe.config;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 /**
  * An immutable map from config paths to config values.
@@ -440,6 +441,8 @@ public interface Config extends ConfigMergeable {
      * href="https://github.com/typesafehub/config/blob/master/HOCON.md">the
      * spec</a>.
      *
+     * @deprecated  As of release 1.1, replaced by {@link #getDuration(String, TimeUnit)}
+     *
      * @param path
      *            path expression
      * @return the duration value at the requested path, in milliseconds
@@ -450,13 +453,15 @@ public interface Config extends ConfigMergeable {
      * @throws ConfigException.BadValue
      *             if value cannot be parsed as a number of milliseconds
      */
-    Long getMilliseconds(String path);
+    @Deprecated Long getMilliseconds(String path);
 
     /**
      * Get value as a duration in nanoseconds. If the value is already a number
      * it's taken as milliseconds and converted to nanoseconds. If it's a
      * string, it's parsed understanding unit suffixes, as for
-     * {@link #getMilliseconds(String)}.
+     * {@link #getDuration(String, TimeUnit)}.
+     *
+     * @deprecated  As of release 1.1, replaced by {@link #getDuration(String, TimeUnit)}
      *
      * @param path
      *            path expression
@@ -468,7 +473,29 @@ public interface Config extends ConfigMergeable {
      * @throws ConfigException.BadValue
      *             if value cannot be parsed as a number of nanoseconds
      */
-    Long getNanoseconds(String path);
+    @Deprecated Long getNanoseconds(String path);
+
+    /**
+     * Get value as a duration in a specified TimeUnit. Naturally the precision will depend on the configured value.
+     * If the value is already a
+     * number, then it's interpreted to be in Milliseconds and then be converted to the requested TimeUnit;
+     * if it's a string, it's parsed understanding units suffixes like "10m" or "5ns" as documented in the <a
+     * href="https://github.com/typesafehub/config/blob/master/HOCON.md">the
+     * spec</a>.
+     *
+     * @param path
+     *            path expression
+     * @param unit
+     *            The TimeUnit in which the returned long should be
+     * @return the duration value at the requested path, in the given TimeUnit
+     * @throws ConfigException.Missing
+     *             if value is absent or null
+     * @throws ConfigException.WrongType
+     *             if value is not convertible to Long or String
+     * @throws ConfigException.BadValue
+     *             if value cannot be parsed as a number of the given TimeUnit
+     */
+    Long getDuration(String path, TimeUnit unit);
 
     /**
      * Gets a list value (with any element type) as a {@link ConfigList}, which
@@ -505,9 +532,17 @@ public interface Config extends ConfigMergeable {
 
     List<Long> getBytesList(String path);
 
-    List<Long> getMillisecondsList(String path);
+    /**
+     * @deprecated  As of release 1.1, replaced by {@link #getDurationList(String, TimeUnit)}
+     */
+    @Deprecated List<Long> getMillisecondsList(String path);
 
-    List<Long> getNanosecondsList(String path);
+    /**
+     * @deprecated  As of release 1.1, replaced by {@link #getDurationList(String, TimeUnit)}
+     */
+    @Deprecated List<Long> getNanosecondsList(String path);
+
+    List<Long> getDurationList(String path, TimeUnit unit);
 
     /**
      * Clone the config with only the given path (and its children) retained;
diff --git a/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java b/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java
index d368e144..2cf5bab8 100644
--- a/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java
+++ b/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java
@@ -234,23 +234,30 @@ final class SimpleConfig implements Config, MergeableValue, Serializable {
         return size;
     }
 
+    @Deprecated
     @Override
     public Long getMilliseconds(String path) {
-        long ns = getNanoseconds(path);
-        long ms = TimeUnit.NANOSECONDS.toMillis(ns);
-        return ms;
+        return getDuration(path, TimeUnit.MILLISECONDS);
+    }
+
+    @Deprecated
+    @Override
+    public Long getNanoseconds(String path) {
+        return getDuration(path, TimeUnit.NANOSECONDS);
     }
 
     @Override
-    public Long getNanoseconds(String path) {
-        Long ns = null;
+    public Long getDuration(String path, TimeUnit unit) {
+        Long result = null;
         try {
-            ns = TimeUnit.MILLISECONDS.toNanos(getLong(path));
+            result = unit.convert(getLong(path), TimeUnit.MILLISECONDS);
         } catch (ConfigException.WrongType e) {
             ConfigValue v = find(path, ConfigValueType.STRING);
-            ns = parseDuration((String) v.unwrapped(), v.origin(), path);
+            result = unit.convert(
+                       parseDuration((String) v.unwrapped(), v.origin(), path),
+                       TimeUnit.NANOSECONDS);
         }
-        return ns;
+        return result;
     }
 
     @SuppressWarnings("unchecked")
@@ -384,36 +391,42 @@ final class SimpleConfig implements Config, MergeableValue, Serializable {
     }
 
     @Override
-    public List<Long> getMillisecondsList(String path) {
-        List<Long> nanos = getNanosecondsList(path);
-        List<Long> l = new ArrayList<Long>();
-        for (Long n : nanos) {
-            l.add(TimeUnit.NANOSECONDS.toMillis(n));
-        }
-        return l;
-    }
-
-    @Override
-    public List<Long> getNanosecondsList(String path) {
+    public List<Long> getDurationList(String path, TimeUnit unit) {
         List<Long> l = new ArrayList<Long>();
         List<? extends ConfigValue> list = getList(path);
         for (ConfigValue v : list) {
             if (v.valueType() == ConfigValueType.NUMBER) {
-                l.add(TimeUnit.MILLISECONDS.toNanos(((Number) v.unwrapped())
-                        .longValue()));
+                Long n = unit.convert(
+                           ((Number) v.unwrapped()).longValue(),
+                           TimeUnit.MILLISECONDS);
+                l.add(n);
             } else if (v.valueType() == ConfigValueType.STRING) {
                 String s = (String) v.unwrapped();
-                Long n = parseDuration(s, v.origin(), path);
+                Long n = unit.convert(
+                           parseDuration(s, v.origin(), path),
+                           TimeUnit.NANOSECONDS);
                 l.add(n);
             } else {
                 throw new ConfigException.WrongType(v.origin(), path,
-                        "duration string or number of nanoseconds", v
-                                .valueType().name());
+                        "duration string or number of " + unit.name(),
+                        v.valueType().name());
             }
         }
         return l;
     }
 
+    @Deprecated
+    @Override
+    public List<Long> getMillisecondsList(String path) {
+        return getDurationList(path, TimeUnit.MILLISECONDS);
+    }
+
+    @Deprecated
+    @Override
+    public List<Long> getNanosecondsList(String path) {
+        return getDurationList(path, TimeUnit.NANOSECONDS);
+    }
+
     @Override
     public AbstractConfigObject toFallbackValue() {
         return object;
diff --git a/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala b/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
index 77005bc8..c73a253b 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
@@ -13,6 +13,7 @@ import java.util.concurrent.TimeUnit
 import scala.collection.JavaConverters._
 import com.typesafe.config.ConfigResolveOptions
 import java.io.File
+import java.util.concurrent.TimeUnit.{ SECONDS, NANOSECONDS, MICROSECONDS, MILLISECONDS, MINUTES, DAYS, HOURS }
 import com.typesafe.config.ConfigParseOptions
 import com.typesafe.config.ConfigFactory
 import com.typesafe.config.ConfigMergeable
@@ -736,6 +737,28 @@ class ConfigTest extends TestUtils {
             conf.getNanosecondsList("durations.secondsList").asScala)
         assertEquals(500L, conf.getMilliseconds("durations.halfSecond"))
 
+        def assertDurationAsTimeUnit(unit: TimeUnit): Unit = {
+          def ms2unit(l: Long) = unit.convert(l, MILLISECONDS)
+          def s2unit(i: Int) = unit.convert(i, SECONDS)
+          assertEquals(ms2unit(1000L), conf.getDuration("durations.second", unit))
+          assertEquals(s2unit(1), conf.getDuration("durations.second", unit))
+          assertEquals(ms2unit(1000L), conf.getDuration("durations.secondAsNumber", unit))
+          assertEquals(s2unit(1), conf.getDuration("durations.secondAsNumber", unit))
+          assertEquals(Seq(1000L, 2000L, 3000L, 4000L) map ms2unit,
+            conf.getDurationList("durations.secondsList", unit).asScala)
+          assertEquals(Seq(1, 2, 3, 4) map s2unit,
+            conf.getDurationList("durations.secondsList", unit).asScala)
+          assertEquals(ms2unit(500L), conf.getDuration("durations.halfSecond", unit))
+        }
+
+        assertDurationAsTimeUnit(NANOSECONDS)
+        assertDurationAsTimeUnit(MICROSECONDS)
+        assertDurationAsTimeUnit(MILLISECONDS)
+        assertDurationAsTimeUnit(SECONDS)
+        assertDurationAsTimeUnit(MINUTES)
+        assertDurationAsTimeUnit(HOURS)
+        assertDurationAsTimeUnit(DAYS)
+
         // should get size in bytes
         assertEquals(1024 * 1024L, conf.getBytes("memsizes.meg"))
         assertEquals(1024 * 1024L, conf.getBytes("memsizes.megAsNumber"))

From 91ec79f976f82a064453d9111c9bb9d9c73c8e88 Mon Sep 17 00:00:00 2001
From: Havoc Pennington <hp@pobox.com>
Date: Fri, 21 Jun 2013 10:17:28 -0400
Subject: [PATCH 3/4] add @since to getDuration, and minor doc tweaks

---
 .../main/java/com/typesafe/config/Config.java | 28 ++++++++++++++-----
 1 file changed, 21 insertions(+), 7 deletions(-)

diff --git a/config/src/main/java/com/typesafe/config/Config.java b/config/src/main/java/com/typesafe/config/Config.java
index 47f0e728..42e4df0c 100644
--- a/config/src/main/java/com/typesafe/config/Config.java
+++ b/config/src/main/java/com/typesafe/config/Config.java
@@ -476,17 +476,20 @@ public interface Config extends ConfigMergeable {
     @Deprecated Long getNanoseconds(String path);
 
     /**
-     * Get value as a duration in a specified TimeUnit. Naturally the precision will depend on the configured value.
-     * If the value is already a
-     * number, then it's interpreted to be in Milliseconds and then be converted to the requested TimeUnit;
-     * if it's a string, it's parsed understanding units suffixes like "10m" or "5ns" as documented in the <a
+     * Gets a value as a duration in a specified
+     * {@link java.util.concurrent.TimeUnit TimeUnit}. If the value is already a
+     * number, then it's taken as milliseconds and then converted to the
+     * requested TimeUnit; if it's a string, it's parsed understanding units
+     * suffixes like "10m" or "5ns" as documented in the <a
      * href="https://github.com/typesafehub/config/blob/master/HOCON.md">the
      * spec</a>.
-     *
+     * 
+     * @since 1.1
+     * 
      * @param path
      *            path expression
      * @param unit
-     *            The TimeUnit in which the returned long should be
+     *            convert the return value to this time unit
      * @return the duration value at the requested path, in the given TimeUnit
      * @throws ConfigException.Missing
      *             if value is absent or null
@@ -542,6 +545,17 @@ public interface Config extends ConfigMergeable {
      */
     @Deprecated List<Long> getNanosecondsList(String path);
 
+    /**
+     * Gets a list, converting each value in the list to a duration, using the
+     * same rules as {@link #getDuration(String, TimeUnit)}.
+     *
+     * @since 1.1
+     * @param path
+     *            a path expression
+     * @param unit
+     *            time units of the returned values
+     * @return list of durations, in the requested units
+     */
     List<Long> getDurationList(String path, TimeUnit unit);
 
     /**
@@ -589,7 +603,7 @@ public interface Config extends ConfigMergeable {
      * to the given value. Does not modify this instance (since it's immutable).
      * If the path already has a value, that value is replaced. To remove a
      * value, use withoutPath().
-     * 
+     *
      * @param path
      *            path to add
      * @param value

From c6cd729746b70d7f5c761137c18f2c2e71c74245 Mon Sep 17 00:00:00 2001
From: Havoc Pennington <hp@pobox.com>
Date: Fri, 21 Jun 2013 10:21:50 -0400
Subject: [PATCH 4/4] Fix exception text for bad duration value

It said it expected a string or number of $units,
but really if it's a number it always has to be
milliseconds.
---
 config/src/main/java/com/typesafe/config/impl/SimpleConfig.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java b/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java
index 2cf5bab8..924340d0 100644
--- a/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java
+++ b/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java
@@ -408,7 +408,7 @@ final class SimpleConfig implements Config, MergeableValue, Serializable {
                 l.add(n);
             } else {
                 throw new ConfigException.WrongType(v.origin(), path,
-                        "duration string or number of " + unit.name(),
+                        "duration string or number of milliseconds",
                         v.valueType().name());
             }
         }