/* 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.TimeZone;

public class DateTimeHelper {

  private DateTimeHelper() {
  }

  public static final long ONE_SECOND = 1000L,
      TEN_SECONDS = 10L * ONE_SECOND,
      ONE_MINUTE = 60L * ONE_SECOND,
      FIVE_MINUTES = 5L * ONE_MINUTE,
      FIFTEEN_MINUTES = 15L * ONE_MINUTE,
      ONE_HOUR = 60L * ONE_MINUTE,
      FOUR_HOURS = 4L * ONE_HOUR,
      SIX_HOURS = 6L * ONE_HOUR,
      TWELVE_HOURS = 12L * ONE_HOUR,
      ONE_DAY = 24L * ONE_HOUR,
      TWO_DAYS = 2L * ONE_DAY,
      THREE_DAYS = 3L * ONE_DAY,
      ONE_WEEK = 7L * ONE_DAY,
      TEN_DAYS = 10L * ONE_DAY,
      ROUGHLY_ONE_MONTH = 31L * ONE_DAY,
      ROUGHLY_THREE_MONTHS = 92L * ONE_DAY,
      ROUGHLY_ONE_YEAR = 366L * ONE_DAY,
      ROUGHLY_FIVE_YEARS = 5L * ROUGHLY_ONE_YEAR;

  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 DATEHOUR_NOSPACE_FORMAT = "yyyy-MM-dd-HH";

  private static DateFormat getDateFormat(String format) {
    /* TODO We're creating a new SimpleDateFormat instance here, because
     * we can't share a single instance per date format between multiple
     * threads.  A better solution would be to share a single instance per
     * date format and thread, or to share an instance of a thread-safe
     * alternative per date format. */
    DateFormat dateFormat = new SimpleDateFormat(format);
    dateFormat.setLenient(false);
    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    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);
  }
}


@@ -193,32 +193,80 @@
 mpleDateFormat;%0A
+import java.util.HashMap;%0Aimport java.util.Map;%0A
 import java.util
@@ -1338,89 +1338,212 @@
 tic 
-DateFormat getDateFormat(String format) %7B%0A    /* TODO We're creating a new Simple
+ThreadLocal%3CMap%3CString, DateFormat%3E%3E dateFormats =%0A      new ThreadLocal%3CMap%3CString, DateFormat%3E%3E () %7B%0A    public Map%3CString, DateFormat%3E get() %7B%0A      return super.get();%0A    %7D%0A    protected Map%3CString, 
 Date
@@ -1552,295 +1552,407 @@
 rmat
+%3E
  in
-stance here, because%0A     * we can't share a single instance per date f
+itialValue() %7B%0A      return new HashMap%3CString, DateF
 ormat
- between multiple%0A     * threads.  A better solution would be to share a single instance per%0A     * date format and thread, or to share an instance of a thread-safe%0A     * alternative per date 
+%3E();%0A    %7D%0A    public void remove() %7B%0A      super.remove();%0A    %7D%0A    public void set(Map%3CString, DateFormat%3E value) %7B%0A      super.set(value);%0A    %7D%0A  %7D;%0A%0A  private static DateFormat getDateFormat(String format) %7B%0A    Map%3CString, DateFormat%3E threadDateFormats = dateFormats.get();%0A    if (!threadDateFormats.containsKey(
 format
-. */
+)) %7B
 %0A    
+  
 Date
@@ -2001,24 +2001,26 @@
 ormat);%0A    
+  
 dateFormat.s
@@ -2037,24 +2037,26 @@
 false);%0A    
+  
 dateFormat.s
@@ -2104,25 +2104,99 @@
     
-return dateFormat
+  threadDateFormats.put(format, dateFormat);%0A    %7D%0A    return threadDateFormats.get(format)
 ;%0A  

Use a single DateFormat per thread and format.