[tor-commits] [onionoo/master] Move date parsing and formatting to util class.

karsten at torproject.org karsten at torproject.org
Mon Apr 14 13:29:24 UTC 2014


commit 14a6e590853aaf8e151125bf8ae60ed82b654cf3
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date:   Tue Apr 8 23:17:32 2014 +0200

    Move date parsing and formatting to util class.
    
    Suggested by SonarQube to avoid code repetition.
---
 .../onionoo/BandwidthDocumentWriter.java           |   11 +--
 src/org/torproject/onionoo/BandwidthStatus.java    |   85 ++++++++----------
 .../torproject/onionoo/BandwidthStatusUpdater.java |   42 ++++-----
 .../torproject/onionoo/ClientsDocumentWriter.java  |    9 +-
 src/org/torproject/onionoo/ClientsStatus.java      |   25 ++----
 .../torproject/onionoo/ClientsStatusUpdater.java   |    7 +-
 src/org/torproject/onionoo/DateTimeHelper.java     |   57 +++++++++++++
 .../torproject/onionoo/DetailsDocumentWriter.java  |   18 ++--
 .../onionoo/NodeDetailsStatusUpdater.java          |   18 +---
 src/org/torproject/onionoo/NodeStatus.java         |   55 ++++++------
 src/org/torproject/onionoo/ResponseBuilder.java    |    9 +-
 .../torproject/onionoo/UptimeDocumentWriter.java   |    9 +-
 src/org/torproject/onionoo/UptimeStatus.java       |   21 ++---
 .../torproject/onionoo/WeightsDocumentWriter.java  |    9 +-
 src/org/torproject/onionoo/WeightsStatus.java      |   90 +++++++++-----------
 .../torproject/onionoo/WeightsStatusUpdater.java   |    7 +-
 16 files changed, 209 insertions(+), 263 deletions(-)

diff --git a/src/org/torproject/onionoo/BandwidthDocumentWriter.java b/src/org/torproject/onionoo/BandwidthDocumentWriter.java
index 754c8f3..68912c7 100644
--- a/src/org/torproject/onionoo/BandwidthDocumentWriter.java
+++ b/src/org/torproject/onionoo/BandwidthDocumentWriter.java
@@ -2,7 +2,6 @@
  * See LICENSE for licensing information */
 package org.torproject.onionoo;
 
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -10,7 +9,6 @@ import java.util.Locale;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
-import java.util.TimeZone;
 
 public class BandwidthDocumentWriter implements FingerprintListener,
     DocumentWriter{
@@ -21,16 +19,11 @@ public class BandwidthDocumentWriter implements FingerprintListener,
 
   private long now;
 
-  private SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-      "yyyy-MM-dd HH:mm:ss");
-
   public BandwidthDocumentWriter(DescriptorSource descriptorSource,
       DocumentStore documentStore, Time time) {
     this.descriptorSource = descriptorSource;
     this.documentStore = documentStore;
     this.now = time.currentTimeMillis();
-    this.dateTimeFormat.setLenient(false);
-    this.dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     this.registerFingerprintListeners();
   }
 
@@ -161,9 +154,9 @@ public class BandwidthDocumentWriter implements FingerprintListener,
       StringBuilder sb2 = new StringBuilder();
       sb2.append("\"" + graphName + "\":{"
           + "\"first\":\""
-          + this.dateTimeFormat.format(firstDataPointMillis) + "\","
+          + DateTimeHelper.format(firstDataPointMillis) + "\","
           + "\"last\":\""
-          + this.dateTimeFormat.format(lastDataPointMillis) + "\","
+          + DateTimeHelper.format(lastDataPointMillis) + "\","
           +"\"interval\":" + String.valueOf(dataPointInterval / 1000L)
           + ",\"factor\":" + String.format(Locale.US, "%.3f", factor)
           + ",\"count\":" + String.valueOf(count) + ",\"values\":[");
diff --git a/src/org/torproject/onionoo/BandwidthStatus.java b/src/org/torproject/onionoo/BandwidthStatus.java
index fd3c36e..00e8ca8 100644
--- a/src/org/torproject/onionoo/BandwidthStatus.java
+++ b/src/org/torproject/onionoo/BandwidthStatus.java
@@ -2,11 +2,8 @@
  * See LICENSE for licensing information */
 package org.torproject.onionoo;
 
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
 import java.util.Scanner;
 import java.util.SortedMap;
-import java.util.TimeZone;
 import java.util.TreeMap;
 
 class BandwidthStatus extends Document {
@@ -16,62 +13,50 @@ class BandwidthStatus extends Document {
   SortedMap<Long, long[]> readHistory = new TreeMap<Long, long[]>();
 
   public void fromDocumentString(String documentString) {
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-        "yyyy-MM-dd HH:mm:ss");
-    dateTimeFormat.setLenient(false);
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
-    try {
-      Scanner s = new Scanner(documentString);
-      while (s.hasNextLine()) {
-        String line = s.nextLine();
-        String[] parts = line.split(" ");
-        if (parts.length != 6) {
-          System.err.println("Illegal line '" + line + "' in bandwidth "
-              + "history.  Skipping this line.");
-          continue;
-        }
-        SortedMap<Long, long[]> history = parts[0].equals("r")
-            ? readHistory : writeHistory;
-        long startMillis = dateTimeFormat.parse(parts[1] + " "
-            + parts[2]).getTime();
-        long endMillis = dateTimeFormat.parse(parts[3] + " "
-            + parts[4]).getTime();
-        long bandwidth = Long.parseLong(parts[5]);
-        long previousEndMillis = history.headMap(startMillis).isEmpty()
-            ? startMillis
-            : history.get(history.headMap(startMillis).lastKey())[1];
-        long nextStartMillis = history.tailMap(startMillis).isEmpty()
-            ? endMillis : history.tailMap(startMillis).firstKey();
-        if (previousEndMillis <= startMillis &&
-            nextStartMillis >= endMillis) {
-          history.put(startMillis, new long[] { startMillis, endMillis,
-              bandwidth });
-        }
+    Scanner s = new Scanner(documentString);
+    while (s.hasNextLine()) {
+      String line = s.nextLine();
+      String[] parts = line.split(" ");
+      if (parts.length != 6) {
+        System.err.println("Illegal line '" + line + "' in bandwidth "
+            + "history.  Skipping this line.");
+        continue;
+      }
+      SortedMap<Long, long[]> history = parts[0].equals("r")
+          ? readHistory : writeHistory;
+      long startMillis = DateTimeHelper.parse(parts[1] + " " + parts[2]);
+      long endMillis = DateTimeHelper.parse(parts[3] + " " + parts[4]);
+      if (startMillis < 0L || endMillis < 0L) {
+        System.err.println("Could not parse timestamp while reading "
+            + "bandwidth history.  Skipping.");
+        break;
+      }
+      long bandwidth = Long.parseLong(parts[5]);
+      long previousEndMillis = history.headMap(startMillis).isEmpty()
+          ? startMillis
+          : history.get(history.headMap(startMillis).lastKey())[1];
+      long nextStartMillis = history.tailMap(startMillis).isEmpty()
+          ? endMillis : history.tailMap(startMillis).firstKey();
+      if (previousEndMillis <= startMillis &&
+          nextStartMillis >= endMillis) {
+        history.put(startMillis, new long[] { startMillis, endMillis,
+            bandwidth });
       }
-      s.close();
-    } catch (ParseException e) {
-      System.err.println("Could not parse timestamp while reading "
-          + "bandwidth history.  Skipping.");
-      e.printStackTrace();
     }
-
+    s.close();
   }
 
   public String toDocumentString() {
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-        "yyyy-MM-dd HH:mm:ss");
-    dateTimeFormat.setLenient(false);
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     StringBuilder sb = new StringBuilder();
     for (long[] v : writeHistory.values()) {
-      sb.append("w " + dateTimeFormat.format(v[0]) + " "
-          + dateTimeFormat.format(v[1]) + " "
-          + String.valueOf(v[2]) + "\n");
+      sb.append("w " + DateTimeHelper.format(v[0]) + " "
+          + DateTimeHelper.format(v[1]) + " " + String.valueOf(v[2])
+          + "\n");
     }
     for (long[] v : readHistory.values()) {
-      sb.append("r " + dateTimeFormat.format(v[0]) + " "
-          + dateTimeFormat.format(v[1]) + " "
-          + String.valueOf(v[2]) + "\n");
+      sb.append("r " + DateTimeHelper.format(v[0]) + " "
+          + DateTimeHelper.format(v[1]) + " " + String.valueOf(v[2])
+          + "\n");
     }
     return sb.toString();
   }
diff --git a/src/org/torproject/onionoo/BandwidthStatusUpdater.java b/src/org/torproject/onionoo/BandwidthStatusUpdater.java
index 6254260..cce56bc 100644
--- a/src/org/torproject/onionoo/BandwidthStatusUpdater.java
+++ b/src/org/torproject/onionoo/BandwidthStatusUpdater.java
@@ -2,10 +2,7 @@
  * See LICENSE for licensing information */
 package org.torproject.onionoo;
 
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
 import java.util.SortedMap;
-import java.util.TimeZone;
 import java.util.TreeMap;
 
 import org.torproject.descriptor.Descriptor;
@@ -20,16 +17,11 @@ public class BandwidthStatusUpdater implements DescriptorListener,
 
   private long now;
 
-  private SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-      "yyyy-MM-dd HH:mm:ss");
-
   public BandwidthStatusUpdater(DescriptorSource descriptorSource,
       DocumentStore documentStore, Time time) {
     this.descriptorSource = descriptorSource;
     this.documentStore = documentStore;
     this.now = time.currentTimeMillis();
-    this.dateTimeFormat.setLenient(false);
-    this.dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     this.registerDescriptorListeners();
   }
 
@@ -76,23 +68,22 @@ public class BandwidthStatusUpdater implements DescriptorListener,
     if (parts.length < 6) {
       return;
     }
-    try {
-      long endMillis = this.dateTimeFormat.parse(parts[1] + " "
-          + parts[2]).getTime();
-      long intervalMillis = Long.parseLong(parts[3].substring(1)) * 1000L;
-      String[] values = parts[5].split(",");
-      for (int i = values.length - 1; i >= 0; i--) {
-        long bandwidthValue = Long.parseLong(values[i]);
-        long startMillis = endMillis - intervalMillis;
-        /* TODO Should we first check whether an interval is already
-         * contained in history? */
-        history.put(startMillis, new long[] { startMillis, endMillis,
-            bandwidthValue });
-        endMillis -= intervalMillis;
-      }
-    } catch (ParseException e) {
+    long endMillis = DateTimeHelper.parse(parts[1] + " " + parts[2]);
+    if (endMillis < 0L) {
       System.err.println("Could not parse timestamp in line '" + line
           + "'.  Skipping.");
+      return;
+    }
+    long intervalMillis = Long.parseLong(parts[3].substring(1)) * 1000L;
+    String[] values = parts[5].split(",");
+    for (int i = values.length - 1; i >= 0; i--) {
+      long bandwidthValue = Long.parseLong(values[i]);
+      long startMillis = endMillis - intervalMillis;
+      /* TODO Should we first check whether an interval is already
+       * contained in history? */
+      history.put(startMillis, new long[] { startMillis, endMillis,
+          bandwidthValue });
+      endMillis -= intervalMillis;
     }
   }
 
@@ -101,8 +92,6 @@ public class BandwidthStatusUpdater implements DescriptorListener,
         new TreeMap<Long, long[]>(history);
     history.clear();
     long lastStartMillis = 0L, lastEndMillis = 0L, lastBandwidth = 0L;
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM");
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     String lastMonthString = "1970-01";
     for (long[] v : uncompressedHistory.values()) {
       long startMillis = v[0], endMillis = v[1], bandwidth = v[2];
@@ -120,7 +109,8 @@ public class BandwidthStatusUpdater implements DescriptorListener,
       } else {
         intervalLengthMillis = 10L * 24L * 60L * 60L * 1000L;
       }
-      String monthString = dateTimeFormat.format(startMillis);
+      String monthString = DateTimeHelper.format(startMillis,
+          DateTimeHelper.ISO_YEARMONTH_FORMAT);
       if (lastEndMillis == startMillis &&
           ((lastEndMillis - 1L) / intervalLengthMillis) ==
           ((endMillis - 1L) / intervalLengthMillis) &&
diff --git a/src/org/torproject/onionoo/ClientsDocumentWriter.java b/src/org/torproject/onionoo/ClientsDocumentWriter.java
index 9d3b8dc..fe400d2 100644
--- a/src/org/torproject/onionoo/ClientsDocumentWriter.java
+++ b/src/org/torproject/onionoo/ClientsDocumentWriter.java
@@ -2,14 +2,12 @@
  * See LICENSE for licensing information */
 package org.torproject.onionoo;
 
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.SortedMap;
 import java.util.SortedSet;
-import java.util.TimeZone;
 import java.util.TreeMap;
 import java.util.TreeSet;
 
@@ -221,12 +219,9 @@ public class ClientsDocumentWriter implements FingerprintListener,
     double factor = ((double) maxValue) / 999.0;
     int count = lastNonNullIndex - firstNonNullIndex + 1;
     StringBuilder sb = new StringBuilder();
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-        "yyyy-MM-dd HH:mm:ss");
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     sb.append("\"" + graphName + "\":{"
-        + "\"first\":\"" + dateTimeFormat.format(firstDataPointMillis)
-        + "\",\"last\":\"" + dateTimeFormat.format(lastDataPointMillis)
+        + "\"first\":\"" + DateTimeHelper.format(firstDataPointMillis)
+        + "\",\"last\":\"" + DateTimeHelper.format(lastDataPointMillis)
         + "\",\"interval\":" + String.valueOf(dataPointInterval / 1000L)
         + ",\"factor\":" + String.format(Locale.US, "%.9f", factor)
         + ",\"count\":" + String.valueOf(count) + ",\"values\":[");
diff --git a/src/org/torproject/onionoo/ClientsStatus.java b/src/org/torproject/onionoo/ClientsStatus.java
index c1ce80e..26f9eab 100644
--- a/src/org/torproject/onionoo/ClientsStatus.java
+++ b/src/org/torproject/onionoo/ClientsStatus.java
@@ -2,13 +2,10 @@
  * See LICENSE for licensing information */
 package org.torproject.onionoo;
 
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
 import java.util.Map;
 import java.util.Scanner;
 import java.util.SortedMap;
 import java.util.SortedSet;
-import java.util.TimeZone;
 import java.util.TreeMap;
 import java.util.TreeSet;
 
@@ -45,17 +42,9 @@ class ClientsHistory implements Comparable<ClientsHistory> {
     if (parts.length != 8) {
       return null;
     }
-    long startMillis = -1L, endMillis = -1L;
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-        "yyyy-MM-dd HH:mm:ss");
-    dateTimeFormat.setLenient(false);
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
-    try {
-      startMillis = dateTimeFormat.parse(parts[0] + " " + parts[1]).
-          getTime();
-      endMillis = dateTimeFormat.parse(parts[2] + " " + parts[3]).
-          getTime();
-    } catch (ParseException e) {
+    long startMillis = DateTimeHelper.parse(parts[0] + " " + parts[1]);
+    long endMillis = DateTimeHelper.parse(parts[2] + " " + parts[3]);
+    if (startMillis < 0L || endMillis < 0L) {
       return null;
     }
     if (startMillis >= endMillis) {
@@ -104,12 +93,8 @@ class ClientsHistory implements Comparable<ClientsHistory> {
 
   public String toString() {
     StringBuilder sb = new StringBuilder();
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-        "yyyy-MM-dd HH:mm:ss");
-    dateTimeFormat.setLenient(false);
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
-    sb.append(dateTimeFormat.format(startMillis));
-    sb.append(" " + dateTimeFormat.format(endMillis));
+    sb.append(DateTimeHelper.format(startMillis));
+    sb.append(" " + DateTimeHelper.format(endMillis));
     sb.append(" " + String.format("%.3f", this.totalResponses));
     this.appendResponses(sb, this.responsesByCountry);
     this.appendResponses(sb, this.responsesByTransport);
diff --git a/src/org/torproject/onionoo/ClientsStatusUpdater.java b/src/org/torproject/onionoo/ClientsStatusUpdater.java
index e15c11a..0ce550f 100644
--- a/src/org/torproject/onionoo/ClientsStatusUpdater.java
+++ b/src/org/torproject/onionoo/ClientsStatusUpdater.java
@@ -2,11 +2,9 @@
  * See LICENSE for licensing information */
 package org.torproject.onionoo;
 
-import java.text.SimpleDateFormat;
 import java.util.Map;
 import java.util.SortedMap;
 import java.util.SortedSet;
-import java.util.TimeZone;
 import java.util.TreeMap;
 import java.util.TreeSet;
 
@@ -177,8 +175,6 @@ public class ClientsStatusUpdater implements DescriptorListener,
     SortedSet<ClientsHistory> compressedHistory =
         new TreeSet<ClientsHistory>();
     ClientsHistory lastResponses = null;
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM");
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     String lastMonthString = "1970-01";
     for (ClientsHistory responses : history) {
       long intervalLengthMillis;
@@ -191,7 +187,8 @@ public class ClientsStatusUpdater implements DescriptorListener,
       } else {
         intervalLengthMillis = 10L * 24L * 60L * 60L * 1000L;
       }
-      String monthString = dateTimeFormat.format(responses.startMillis);
+      String monthString = DateTimeHelper.format(responses.startMillis,
+          DateTimeHelper.ISO_YEARMONTH_FORMAT);
       if (lastResponses != null &&
           lastResponses.endMillis == responses.startMillis &&
           ((lastResponses.endMillis - 1L) / intervalLengthMillis) ==
diff --git a/src/org/torproject/onionoo/DateTimeHelper.java b/src/org/torproject/onionoo/DateTimeHelper.java
new file mode 100644
index 0000000..f97c8c5
--- /dev/null
+++ b/src/org/torproject/onionoo/DateTimeHelper.java
@@ -0,0 +1,57 @@
+/* Copyright 2014 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.onionoo;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+public class DateTimeHelper {
+
+  public static final String ISO_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
+
+  public static final String ISO_DATETIME_TAB_FORMAT =
+      "yyyy-MM-dd\tHH:mm:ss";
+
+  public static final String ISO_YEARMONTH_FORMAT = "yyyy-MM";
+
+  public static final String YEARHOUR_NOSPACE_FORMAT = "yyyy-MM-dd-HH";
+
+  private static Map<String, DateFormat> dateFormats =
+      new HashMap<String, DateFormat>();
+
+  private static DateFormat getDateFormat(String format) {
+    DateFormat dateFormat = dateFormats.get(format);
+    if (dateFormat == null) {
+      dateFormat = new SimpleDateFormat(format);
+      dateFormat.setLenient(false);
+      dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+      dateFormats.put(format, dateFormat);
+    }
+    return dateFormat;
+  }
+
+  public static String format(long millis, String format) {
+    return getDateFormat(format).format(millis);
+  }
+
+  public static String format(long millis) {
+    return format(millis, ISO_DATETIME_FORMAT);
+  }
+
+  public static long parse(String string, String format) {
+    try {
+      return getDateFormat(format).parse(string).getTime();
+    } catch (ParseException e) {
+      return -1L;
+    }
+  }
+
+  public static long parse(String string) {
+    return parse(string, ISO_DATETIME_FORMAT);
+  }
+}
+
diff --git a/src/org/torproject/onionoo/DetailsDocumentWriter.java b/src/org/torproject/onionoo/DetailsDocumentWriter.java
index 0fd47c5..57d0877 100644
--- a/src/org/torproject/onionoo/DetailsDocumentWriter.java
+++ b/src/org/torproject/onionoo/DetailsDocumentWriter.java
@@ -1,6 +1,5 @@
 package org.torproject.onionoo;
 
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -9,7 +8,6 @@ import java.util.Map;
 import java.util.Scanner;
 import java.util.Set;
 import java.util.SortedSet;
-import java.util.TimeZone;
 import java.util.TreeSet;
 
 import org.apache.commons.lang.StringEscapeUtils;
@@ -101,9 +99,6 @@ public class DetailsDocumentWriter implements DescriptorListener,
   }
 
   private void updateRelayDetailsFiles() {
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-        "yyyy-MM-dd HH:mm:ss");
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     for (String fingerprint : this.newRelays) {
 
       /* Generate network-status-specific part. */
@@ -124,10 +119,10 @@ public class DetailsDocumentWriter implements DescriptorListener,
             (addressesWritten++ > 0 ? "," : "") + "\""
             + orAddress.toLowerCase() + "\"");
       }
-      String lastSeen = dateTimeFormat.format(entry.getLastSeenMillis());
-      String firstSeen = dateTimeFormat.format(
+      String lastSeen = DateTimeHelper.format(entry.getLastSeenMillis());
+      String firstSeen = DateTimeHelper.format(
           entry.getFirstSeenMillis());
-      String lastChangedOrAddress = dateTimeFormat.format(
+      String lastChangedOrAddress = DateTimeHelper.format(
           entry.getLastChangedOrAddress());
       String running = entry.getRunning() ? "true" : "false";
       int dirPort = entry.getDirPort();
@@ -302,9 +297,6 @@ public class DetailsDocumentWriter implements DescriptorListener,
   }
 
   private void updateBridgeDetailsFiles() {
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-        "yyyy-MM-dd HH:mm:ss");
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     for (String fingerprint : this.newBridges) {
 
       /* Generate network-status-specific part. */
@@ -314,8 +306,8 @@ public class DetailsDocumentWriter implements DescriptorListener,
         continue;
       }
       String nickname = entry.getNickname();
-      String lastSeen = dateTimeFormat.format(entry.getLastSeenMillis());
-      String firstSeen = dateTimeFormat.format(
+      String lastSeen = DateTimeHelper.format(entry.getLastSeenMillis());
+      String firstSeen = DateTimeHelper.format(
           entry.getFirstSeenMillis());
       String running = entry.getRunning() ? "true" : "false";
       String address = entry.getAddress();
diff --git a/src/org/torproject/onionoo/NodeDetailsStatusUpdater.java b/src/org/torproject/onionoo/NodeDetailsStatusUpdater.java
index 3c67aea..aa245dc 100644
--- a/src/org/torproject/onionoo/NodeDetailsStatusUpdater.java
+++ b/src/org/torproject/onionoo/NodeDetailsStatusUpdater.java
@@ -2,7 +2,6 @@
  * See LICENSE for licensing information */
 package org.torproject.onionoo;
 
-import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -11,7 +10,6 @@ import java.util.Scanner;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
-import java.util.TimeZone;
 import java.util.TreeMap;
 import java.util.TreeSet;
 
@@ -289,12 +287,8 @@ public class NodeDetailsStatusUpdater implements DescriptorListener,
     String fingerprint = descriptor.getFingerprint();
     DetailsStatus detailsStatus = this.documentStore.retrieve(
         DetailsStatus.class, false, fingerprint);
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-        "yyyy-MM-dd HH:mm:ss");
-    dateTimeFormat.setLenient(false);
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     String publishedDateTime =
-        dateTimeFormat.format(descriptor.getPublishedMillis());
+        DateTimeHelper.format(descriptor.getPublishedMillis());
     if (detailsStatus != null) {
       String detailsString = detailsStatus.documentString;
       String descPublishedLine = "\"desc_published\":\""
@@ -313,7 +307,7 @@ public class NodeDetailsStatusUpdater implements DescriptorListener,
       s.close();
     }
     StringBuilder sb = new StringBuilder();
-    String lastRestartedString = dateTimeFormat.format(
+    String lastRestartedString = DateTimeHelper.format(
         descriptor.getPublishedMillis() - descriptor.getUptime() * 1000L);
     int bandwidthRate = descriptor.getBandwidthRate();
     int bandwidthBurst = descriptor.getBandwidthBurst();
@@ -377,12 +371,8 @@ public class NodeDetailsStatusUpdater implements DescriptorListener,
     String fingerprint = descriptor.getFingerprint();
     DetailsStatus detailsStatus = this.documentStore.retrieve(
         DetailsStatus.class, false, fingerprint);
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-        "yyyy-MM-dd HH:mm:ss");
-    dateTimeFormat.setLenient(false);
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     String publishedDateTime =
-        dateTimeFormat.format(descriptor.getPublishedMillis());
+        DateTimeHelper.format(descriptor.getPublishedMillis());
     String poolAssignmentLine = null;
     if (detailsStatus != null) {
       String detailsString = detailsStatus.documentString;
@@ -401,7 +391,7 @@ public class NodeDetailsStatusUpdater implements DescriptorListener,
       s.close();
     }
     StringBuilder sb = new StringBuilder();
-    String lastRestartedString = dateTimeFormat.format(
+    String lastRestartedString = DateTimeHelper.format(
         descriptor.getPublishedMillis() - descriptor.getUptime() * 1000L);
     int advertisedBandwidth = Math.min(descriptor.getBandwidthRate(),
         Math.min(descriptor.getBandwidthBurst(),
diff --git a/src/org/torproject/onionoo/NodeStatus.java b/src/org/torproject/onionoo/NodeStatus.java
index afe2ed3..1c3983e 100644
--- a/src/org/torproject/onionoo/NodeStatus.java
+++ b/src/org/torproject/onionoo/NodeStatus.java
@@ -2,18 +2,15 @@
  * See LICENSE for licensing information */
 package org.torproject.onionoo;
 
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-import java.util.SortedSet;
 import java.util.SortedMap;
-import java.util.TimeZone;
-import java.util.TreeSet;
+import java.util.SortedSet;
 import java.util.TreeMap;
+import java.util.TreeSet;
 
 import org.apache.commons.codec.DecoderException;
 import org.apache.commons.codec.binary.Hex;
@@ -126,9 +123,6 @@ public class NodeStatus extends Document {
     int orPort = -1, dirPort = -1;
     Boolean recommendedVersion = null;
     try {
-      SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-          "yyyy-MM-dd HH:mm:ss");
-      dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
       String separator = documentString.contains("\t") ? "\t" : " ";
       String[] parts = documentString.trim().split(separator);
       isRelay = parts[0].equals("r");
@@ -161,8 +155,12 @@ public class NodeStatus extends Document {
       } else {
         address = addresses;
       }
-      lastSeenMillis = dateTimeFormat.parse(parts[4] + " " + parts[5]).
-          getTime();
+      lastSeenMillis = DateTimeHelper.parse(parts[4] + " " + parts[5]);
+      if (lastSeenMillis < 0L) {
+        System.err.println("Parse exception while parsing node status "
+            + "line '" + documentString + "'.  Skipping.");
+        return null;
+      }
       orPort = Integer.parseInt(parts[6]);
       dirPort = Integer.parseInt(parts[7]);
       relayFlags = new TreeSet<String>();
@@ -189,13 +187,23 @@ public class NodeStatus extends Document {
       }
       firstSeenMillis = lastSeenMillis;
       if (parts.length > 16) {
-        firstSeenMillis = dateTimeFormat.parse(parts[15] + " "
-            + parts[16]).getTime();
+        firstSeenMillis = DateTimeHelper.parse(parts[15] + " "
+            + parts[16]);
+        if (firstSeenMillis < 0L) {
+          System.err.println("Parse exception while parsing node status "
+              + "line '" + documentString + "'.  Skipping.");
+          return null;
+        }
       }
       lastChangedAddresses = lastSeenMillis;
       if (parts.length > 18 && !parts[17].equals("null")) {
-        lastChangedAddresses = dateTimeFormat.parse(parts[17] + " "
-            + parts[18]).getTime();
+        lastChangedAddresses = DateTimeHelper.parse(parts[17] + " "
+            + parts[18]);
+        if (lastChangedAddresses < 0L) {
+          System.err.println("Parse exception while parsing node status "
+              + "line '" + documentString + "'.  Skipping.");
+          return null;
+        }
       }
       if (parts.length > 19) {
         aSNumber = parts[19];
@@ -212,11 +220,6 @@ public class NodeStatus extends Document {
           + "status line '" + documentString + "': " + e.getMessage()
           + ".  Skipping.");
       return null;
-    } catch (ParseException e) {
-      System.err.println("Parse exception while parsing node status "
-          + "line '" + documentString + "': " + e.getMessage() + ".  "
-          + "Skipping.");
-      return null;
     } catch (Exception e) {
       /* This catch block is only here to handle yet unknown errors.  It
        * should go away once we're sure what kind of errors can occur. */
@@ -260,9 +263,6 @@ public class NodeStatus extends Document {
   }
 
   public String toString() {
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-        "yyyy-MM-dd\tHH:mm:ss");
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     StringBuilder sb = new StringBuilder();
     sb.append(this.isRelay ? "r" : "b");
     sb.append("\t" + this.nickname);
@@ -280,7 +280,8 @@ public class NodeStatus extends Document {
             + exitAddress);
       }
     }
-    sb.append("\t" + dateTimeFormat.format(this.lastSeenMillis));
+    sb.append("\t" + DateTimeHelper.format(this.lastSeenMillis,
+        DateTimeHelper.ISO_DATETIME_TAB_FORMAT));
     sb.append("\t" + this.orPort);
     sb.append("\t" + this.dirPort + "\t");
     written = 0;
@@ -299,10 +300,12 @@ public class NodeStatus extends Document {
     } else {
       sb.append("\t-1\t??\tnull\t-1\tnull\tnull");
     }
-    sb.append("\t" + dateTimeFormat.format(this.firstSeenMillis));
+    sb.append("\t" + DateTimeHelper.format(this.firstSeenMillis,
+        DateTimeHelper.ISO_DATETIME_TAB_FORMAT));
     if (this.isRelay) {
-      sb.append("\t" + dateTimeFormat.format(
-          this.getLastChangedOrAddress()));
+      sb.append("\t" + DateTimeHelper.format(
+          this.getLastChangedOrAddress(),
+          DateTimeHelper.ISO_DATETIME_TAB_FORMAT));
       sb.append("\t" + (this.aSNumber != null ? this.aSNumber : "null"));
     } else {
       sb.append("\tnull\tnull\tnull");
diff --git a/src/org/torproject/onionoo/ResponseBuilder.java b/src/org/torproject/onionoo/ResponseBuilder.java
index 1412d88..73ce683 100644
--- a/src/org/torproject/onionoo/ResponseBuilder.java
+++ b/src/org/torproject/onionoo/ResponseBuilder.java
@@ -3,7 +3,6 @@
 package org.torproject.onionoo;
 
 import java.io.PrintWriter;
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -14,7 +13,6 @@ import java.util.Scanner;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
-import java.util.TimeZone;
 import java.util.TreeMap;
 
 public class ResponseBuilder {
@@ -114,12 +112,9 @@ public class ResponseBuilder {
           currentBridges.add(node);
         }
       }
-      SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-          "yyyy-MM-dd HH:mm:ss");
-      dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
-      newRelaysPublishedString = dateTimeFormat.format(
+      newRelaysPublishedString = DateTimeHelper.format(
           relaysLastValidAfterMillis);
-      newBridgesPublishedString = dateTimeFormat.format(
+      newBridgesPublishedString = DateTimeHelper.format(
           bridgesLastPublishedMillis);
       List<String> orderRelaysByConsensusWeight = new ArrayList<String>();
       for (NodeStatus entry : currentRelays) {
diff --git a/src/org/torproject/onionoo/UptimeDocumentWriter.java b/src/org/torproject/onionoo/UptimeDocumentWriter.java
index 5b03153..c53c709 100644
--- a/src/org/torproject/onionoo/UptimeDocumentWriter.java
+++ b/src/org/torproject/onionoo/UptimeDocumentWriter.java
@@ -2,12 +2,10 @@
  * See LICENSE for licensing information */
 package org.torproject.onionoo;
 
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 import java.util.SortedSet;
-import java.util.TimeZone;
 import java.util.TreeSet;
 
 public class UptimeDocumentWriter implements FingerprintListener,
@@ -257,12 +255,9 @@ public class UptimeDocumentWriter implements FingerprintListener,
     double factor = 1.0 / 999.0;
     int count = lastNonNullIndex - firstNonNullIndex + 1;
     StringBuilder sb = new StringBuilder();
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-        "yyyy-MM-dd HH:mm:ss");
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     sb.append("\"" + graphName + "\":{"
-        + "\"first\":\"" + dateTimeFormat.format(firstDataPointMillis)
-        + "\",\"last\":\"" + dateTimeFormat.format(lastDataPointMillis)
+        + "\"first\":\"" + DateTimeHelper.format(firstDataPointMillis)
+        + "\",\"last\":\"" + DateTimeHelper.format(lastDataPointMillis)
         + "\",\"interval\":" + String.valueOf(dataPointInterval / 1000L)
         + ",\"factor\":" + String.format(Locale.US, "%.9f", factor)
         + ",\"count\":" + String.valueOf(count) + ",\"values\":[");
diff --git a/src/org/torproject/onionoo/UptimeStatus.java b/src/org/torproject/onionoo/UptimeStatus.java
index 4d8dca7..0eb9dde 100644
--- a/src/org/torproject/onionoo/UptimeStatus.java
+++ b/src/org/torproject/onionoo/UptimeStatus.java
@@ -2,11 +2,8 @@
  * See LICENSE for licensing information */
 package org.torproject.onionoo;
 
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
 import java.util.Scanner;
 import java.util.SortedSet;
-import java.util.TimeZone;
 import java.util.TreeSet;
 
 class UptimeHistory
@@ -36,14 +33,9 @@ class UptimeHistory
     } else if (!parts[0].equals("b")) {
       return null;
     }
-    long startMillis = -1L;
-    SimpleDateFormat dateHourFormat = new SimpleDateFormat(
-        "yyyy-MM-dd-HH");
-    dateHourFormat.setLenient(false);
-    dateHourFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
-    try {
-      startMillis = dateHourFormat.parse(parts[1]).getTime();
-    } catch (ParseException e) {
+    long startMillis = DateTimeHelper.parse(parts[1],
+          DateTimeHelper.YEARHOUR_NOSPACE_FORMAT);
+    if (startMillis < 0L) {
       return null;
     }
     int uptimeHours = -1;
@@ -57,12 +49,9 @@ class UptimeHistory
 
   public String toString() {
     StringBuilder sb = new StringBuilder();
-    SimpleDateFormat dateHourFormat = new SimpleDateFormat(
-        "yyyy-MM-dd-HH");
-    dateHourFormat.setLenient(false);
-    dateHourFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     sb.append(this.relay ? "r" : "b");
-    sb.append(" " + dateHourFormat.format(this.startMillis));
+    sb.append(" " + DateTimeHelper.format(this.startMillis,
+        DateTimeHelper.YEARHOUR_NOSPACE_FORMAT));
     sb.append(" " + String.format("%d", this.uptimeHours));
     return sb.toString();
   }
diff --git a/src/org/torproject/onionoo/WeightsDocumentWriter.java b/src/org/torproject/onionoo/WeightsDocumentWriter.java
index 9e5355f..6e225f1 100644
--- a/src/org/torproject/onionoo/WeightsDocumentWriter.java
+++ b/src/org/torproject/onionoo/WeightsDocumentWriter.java
@@ -2,7 +2,6 @@
  * See LICENSE for licensing information */
 package org.torproject.onionoo;
 
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -11,7 +10,6 @@ import java.util.Map;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
-import java.util.TimeZone;
 
 public class WeightsDocumentWriter implements FingerprintListener,
     DocumentWriter {
@@ -183,12 +181,9 @@ public class WeightsDocumentWriter implements FingerprintListener,
     double factor = ((double) maxValue) / 999.0;
     int count = lastNonNullIndex - firstNonNullIndex + 1;
     StringBuilder sb = new StringBuilder();
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-        "yyyy-MM-dd HH:mm:ss");
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     sb.append("\"" + graphName + "\":{"
-        + "\"first\":\"" + dateTimeFormat.format(firstDataPointMillis)
-        + "\",\"last\":\"" + dateTimeFormat.format(lastDataPointMillis)
+        + "\"first\":\"" + DateTimeHelper.format(firstDataPointMillis)
+        + "\",\"last\":\"" + DateTimeHelper.format(lastDataPointMillis)
         + "\",\"interval\":" + String.valueOf(dataPointInterval / 1000L)
         + ",\"factor\":" + String.format(Locale.US, "%.9f", factor)
         + ",\"count\":" + String.valueOf(count) + ",\"values\":[");
diff --git a/src/org/torproject/onionoo/WeightsStatus.java b/src/org/torproject/onionoo/WeightsStatus.java
index 4d92f30..93f3087 100644
--- a/src/org/torproject/onionoo/WeightsStatus.java
+++ b/src/org/torproject/onionoo/WeightsStatus.java
@@ -1,13 +1,10 @@
 package org.torproject.onionoo;
 
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Scanner;
 import java.util.SortedMap;
-import java.util.TimeZone;
 import java.util.TreeMap;
 
 class WeightsStatus extends Document {
@@ -23,52 +20,46 @@ class WeightsStatus extends Document {
       new HashMap<String, Integer>();
 
   public void fromDocumentString(String documentString) {
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-        "yyyy-MM-dd HH:mm:ss");
-    dateTimeFormat.setLenient(false);
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
-    try {
-      Scanner s = new Scanner(documentString);
-      while (s.hasNextLine()) {
-        String line = s.nextLine();
-        String[] parts = line.split(" ");
-        if (parts.length == 2) {
-          String descriptorDigest = parts[0];
-          int advertisedBandwidth = Integer.parseInt(parts[1]);
-          this.advertisedBandwidths.put(descriptorDigest,
-              advertisedBandwidth);
-          continue;
-        }
-        if (parts.length != 9) {
-          System.err.println("Illegal line '" + line + "' in weights "
+    Scanner s = new Scanner(documentString);
+    while (s.hasNextLine()) {
+      String line = s.nextLine();
+      String[] parts = line.split(" ");
+      if (parts.length == 2) {
+        String descriptorDigest = parts[0];
+        int advertisedBandwidth = Integer.parseInt(parts[1]);
+        this.advertisedBandwidths.put(descriptorDigest,
+            advertisedBandwidth);
+        continue;
+      }
+      if (parts.length != 9) {
+        System.err.println("Illegal line '" + line + "' in weights "
               + "status file.  Skipping this line.");
-          continue;
-        }
-        if (parts[4].equals("NaN")) {
-          /* Remove corrupt lines written on 2013-07-07 and the days
-           * after. */
-          continue;
-        }
-        long validAfterMillis = dateTimeFormat.parse(parts[0]
-            + " " + parts[1]).getTime();
-        long freshUntilMillis = dateTimeFormat.parse(parts[2]
-            + " " + parts[3]).getTime();
-        long[] interval = new long[] { validAfterMillis,
-            freshUntilMillis };
-        double[] weights = new double[] {
-            Double.parseDouble(parts[4]),
-            Double.parseDouble(parts[5]),
-            Double.parseDouble(parts[6]),
-            Double.parseDouble(parts[7]),
-            Double.parseDouble(parts[8]) };
-        this.history.put(interval, weights);
+        continue;
+      }
+      if (parts[4].equals("NaN")) {
+        /* Remove corrupt lines written on 2013-07-07 and the days
+         * after. */
+        continue;
+      }
+      long validAfterMillis = DateTimeHelper.parse(parts[0] + " "
+          + parts[1]);
+      long freshUntilMillis = DateTimeHelper.parse(parts[2] + " "
+          + parts[3]);
+      if (validAfterMillis < 0L || freshUntilMillis < 0L) {
+        System.err.println("Could not parse timestamp while reading "
+            + "weights status file.  Skipping.");
+        break;
       }
-      s.close();
-    } catch (ParseException e) {
-      System.err.println("Could not parse timestamp while reading "
-          + "weights status file.  Skipping.");
-      e.printStackTrace();
+      long[] interval = new long[] { validAfterMillis, freshUntilMillis };
+      double[] weights = new double[] {
+          Double.parseDouble(parts[4]),
+          Double.parseDouble(parts[5]),
+          Double.parseDouble(parts[6]),
+          Double.parseDouble(parts[7]),
+          Double.parseDouble(parts[8]) };
+      this.history.put(interval, weights);
     }
+    s.close();
   }
 
   public String toDocumentString() {
@@ -77,14 +68,11 @@ class WeightsStatus extends Document {
         this.advertisedBandwidths.entrySet()) {
       sb.append(e.getKey() + " " + String.valueOf(e.getValue()) + "\n");
     }
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat(
-        "yyyy-MM-dd HH:mm:ss");
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     for (Map.Entry<long[], double[]> e : history.entrySet()) {
       long[] fresh = e.getKey();
       double[] weights = e.getValue();
-      sb.append(dateTimeFormat.format(fresh[0]) + " "
-          + dateTimeFormat.format(fresh[1]));
+      sb.append(DateTimeHelper.format(fresh[0]) + " "
+          + DateTimeHelper.format(fresh[1]));
       for (double weight : weights) {
         sb.append(String.format(" %.12f", weight));
       }
diff --git a/src/org/torproject/onionoo/WeightsStatusUpdater.java b/src/org/torproject/onionoo/WeightsStatusUpdater.java
index 79296d3..3438325 100644
--- a/src/org/torproject/onionoo/WeightsStatusUpdater.java
+++ b/src/org/torproject/onionoo/WeightsStatusUpdater.java
@@ -2,7 +2,6 @@
  * See LICENSE for licensing information */
 package org.torproject.onionoo;
 
-import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -10,7 +9,6 @@ import java.util.Map;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
-import java.util.TimeZone;
 import java.util.TreeMap;
 import java.util.TreeSet;
 
@@ -282,8 +280,6 @@ public class WeightsStatusUpdater implements DescriptorListener,
         new TreeMap<long[], double[]>(history.comparator());
     long lastStartMillis = 0L, lastEndMillis = 0L;
     double[] lastWeights = null;
-    SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM");
-    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     String lastMonthString = "1970-01";
     for (Map.Entry<long[], double[]> e : history.entrySet()) {
       long startMillis = e.getKey()[0], endMillis = e.getKey()[1];
@@ -300,7 +296,8 @@ public class WeightsStatusUpdater implements DescriptorListener,
       } else {
         intervalLengthMillis = 10L * 24L * 60L * 60L * 1000L;
       }
-      String monthString = dateTimeFormat.format(startMillis);
+      String monthString = DateTimeHelper.format(startMillis,
+          DateTimeHelper.ISO_YEARMONTH_FORMAT);
       if (lastEndMillis == startMillis &&
           ((lastEndMillis - 1L) / intervalLengthMillis) ==
           ((endMillis - 1L) / intervalLengthMillis) &&






More information about the tor-commits mailing list