From 6daa369bcfbe4b85b0d39391dfbf8e8d238af501 Mon Sep 17 00:00:00 2001 From: jteagles Date: Mon, 2 May 2022 13:14:26 -0500 Subject: [PATCH] YARN-11116. Migrate Times util from SimpleDateFormat to thread-safe DateTimeFormatter class (#4242) Co-authored-by: Jonathan Eagles Signed-off-by: Akira Ajisaka (cherry picked from commit d4a91bd0c0d9d438ffe95fafee0212499b0abcfd) --- .../org/apache/hadoop/yarn/util/Times.java | 33 ++++++++----------- .../apache/hadoop/yarn/util/TestTimes.java | 17 ++++++++++ 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/Times.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/Times.java index 3c415586274..bf6df4c696f 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/Times.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/Times.java @@ -19,8 +19,9 @@ package org.apache.hadoop.yarn.util; import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -30,23 +31,16 @@ import org.apache.hadoop.classification.InterfaceAudience.Private; public class Times { private static final Log LOG = LogFactory.getLog(Times.class); - static final String ISO8601DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; + static final String ISO8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; // This format should match the one used in yarn.dt.plugins.js - static final ThreadLocal dateFormat = - new ThreadLocal() { - @Override protected SimpleDateFormat initialValue() { - return new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy"); - } - }; + static final DateTimeFormatter DATE_FORMAT = + DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss Z yyyy").withZone( + ZoneId.systemDefault()); - static final ThreadLocal isoFormat = - new ThreadLocal() { - @Override - protected SimpleDateFormat initialValue() { - return new SimpleDateFormat(ISO8601DATEFORMAT); - } - }; + static final DateTimeFormatter ISO_OFFSET_DATE_TIME = + DateTimeFormatter.ofPattern(ISO8601_DATE_FORMAT).withZone( + ZoneId.systemDefault()); public static long elapsed(long started, long finished) { return Times.elapsed(started, finished, true); @@ -82,8 +76,7 @@ public class Times { } public static String format(long ts) { - return ts > 0 ? String.valueOf(dateFormat.get().format(new Date(ts))) - : "N/A"; + return ts > 0 ? DATE_FORMAT.format(Instant.ofEpochMilli(ts)) : "N/A"; } /** @@ -93,7 +86,7 @@ public class Times { * @return ISO 8601 formatted string. */ public static String formatISO8601(long ts) { - return isoFormat.get().format(new Date(ts)); + return ISO_OFFSET_DATE_TIME.format(Instant.ofEpochMilli(ts)); } /** @@ -108,6 +101,6 @@ public class Times { if (isoString == null) { throw new ParseException("Invalid input.", -1); } - return isoFormat.get().parse(isoString).getTime(); + return Instant.from(ISO_OFFSET_DATE_TIME.parse(isoString)).toEpochMilli(); } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/util/TestTimes.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/util/TestTimes.java index 918743d02ff..36b94bad554 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/util/TestTimes.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/util/TestTimes.java @@ -21,6 +21,12 @@ package org.apache.hadoop.yarn.util; import org.junit.Assert; import org.junit.Test; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import static org.apache.hadoop.yarn.util.Times.ISO8601_DATE_FORMAT; + public class TestTimes { @Test @@ -61,4 +67,15 @@ public class TestTimes { elapsed = Times.elapsed(Long.MAX_VALUE, 0, true); Assert.assertEquals("Elapsed time is not -1", -1, elapsed); } + + @Test + public void validateISO() throws IOException { + SimpleDateFormat isoFormat = new SimpleDateFormat(ISO8601_DATE_FORMAT); + for (int i = 0; i < 1000; i++) { + long now = System.currentTimeMillis(); + String instant = Times.formatISO8601(now); + String date = isoFormat.format(new Date(now)); + Assert.assertEquals(date, instant); + } + } } \ No newline at end of file