GT-3286 - Timestamp review fixes - move away from SimpleDateFormat to

DateTimeFormatter
This commit is contained in:
dragonmacher 2019-11-05 12:33:26 -05:00
parent 264b7f1b65
commit d3d91697aa
2 changed files with 79 additions and 24 deletions

View file

@ -17,8 +17,10 @@ package ghidra.util;
import static java.util.Calendar.*; import static java.util.Calendar.*;
import java.text.ParseException; import java.time.*;
import java.text.SimpleDateFormat; import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.TemporalAccessor;
import java.util.*; import java.util.*;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
@ -30,14 +32,12 @@ public class DateUtils {
private static final String DATE_FORMAT_STRING = "MM/dd/yyyy"; private static final String DATE_FORMAT_STRING = "MM/dd/yyyy";
private static final String TIME_FORMAT_STRING = "h:mm"; private static final String TIME_FORMAT_STRING = "h:mm";
private static final ThreadLocal<SimpleDateFormat> DATE_TIME_FORMAT = private static final DateTimeFormatter DATE_TIME_FORMATTER =
ThreadLocal.withInitial(() -> new SimpleDateFormat(DATE_TIME_FORMAT_STRING)); DateTimeFormatter.ofPattern(DATE_TIME_FORMAT_STRING);
private static final DateTimeFormatter DATE_FORMATTER =
private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT = DateTimeFormatter.ofPattern(DATE_FORMAT_STRING);
ThreadLocal.withInitial(() -> new SimpleDateFormat(DATE_FORMAT_STRING)); private static final DateTimeFormatter TIME_FORMATTER =
DateTimeFormatter.ofPattern(TIME_FORMAT_STRING);
private static final ThreadLocal<SimpleDateFormat> TIME_FORMAT =
ThreadLocal.withInitial(() -> new SimpleDateFormat(TIME_FORMAT_STRING));
public static final long MS_PER_SEC = 1000; public static final long MS_PER_SEC = 1000;
public static final long MS_PER_MIN = MS_PER_SEC * 60; public static final long MS_PER_MIN = MS_PER_SEC * 60;
@ -182,16 +182,6 @@ public class DateUtils {
} }
} }
public static Date normalizeDate(Date date) {
try {
SimpleDateFormat sdf = DATE_FORMAT.get();
return sdf.parse(sdf.format(date));
}
catch (ParseException e) {
throw new AssertException("Can't happend parsing date from formated date");
}
}
private static Calendar getLastDayOfWeekInMonth(int year, int month, int dayOfWeek) { private static Calendar getLastDayOfWeekInMonth(int year, int month, int dayOfWeek) {
Calendar cal = new GregorianCalendar(year, month, 1); Calendar cal = new GregorianCalendar(year, month, 1);
cal.add(MONTH, 1); cal.add(MONTH, 1);
@ -213,15 +203,27 @@ public class DateUtils {
return dayOfWeek == SATURDAY || dayOfWeek == SUNDAY; return dayOfWeek == SATURDAY || dayOfWeek == SUNDAY;
} }
public static Date normalizeDate(Date date) {
try {
DateTimeFormatter dtf = DATE_FORMATTER;
TemporalAccessor ta = dtf.parse(dtf.format(toLocalDate(date)));
LocalDate localDateTime = LocalDate.from(ta);
return toDate(localDateTime);
}
catch (DateTimeParseException e) {
throw new AssertException("Can't happend parsing date from formated date", e);
}
}
/** /**
* Formats the given date into a string. This is in contrast to * Formats the given date into a string. This is in contrast to
* {@link #formatDateTimestamp(Date)}, which will also return the time portion of the date. * {@link #formatDateTimestamp(Date)}, which will also return the time portion of the date.
* *
* @param date the date to format * @param date the date to format
* @return the date string * @return the date string
*/ */
public static String formatDate(Date date) { public static String formatDate(Date date) {
return DATE_FORMAT.get().format(date); return DATE_FORMATTER.format(toLocalDate(date));
} }
/** /**
@ -232,7 +234,14 @@ public class DateUtils {
* @return the date and time string * @return the date and time string
*/ */
public static String formatDateTimestamp(Date date) { public static String formatDateTimestamp(Date date) {
return DATE_TIME_FORMAT.get().format(date); //@formatter:off
LocalDateTime localDate =
Instant.ofEpochMilli(date.getTime())
.atZone(ZoneId.systemDefault())
.toLocalDateTime()
;
//@formatter:on
return DATE_TIME_FORMATTER.format(toLocalDate(date));
} }
/** /**
@ -242,7 +251,25 @@ public class DateUtils {
* @return current time-of-day a a string * @return current time-of-day a a string
*/ */
public static String formatCurrentTime() { public static String formatCurrentTime() {
return TIME_FORMAT.get().format(new Date()); return TIME_FORMATTER.format(toLocalDate(new Date()));
}
private static LocalDateTime toLocalDate(Date d) {
//@formatter:off
return Instant.ofEpochMilli(d.getTime())
.atZone(ZoneId.systemDefault())
.toLocalDateTime()
;
//@formatter:on
}
private static Date toDate(LocalDate ld) {
//@formatter:off
return Date.from(ld.atStartOfDay()
.atZone(ZoneId.systemDefault())
.toInstant())
;
//@formatter:on
} }
public static Date getDate(int year, int month, int day) { public static Date getDate(int year, int month, int day) {

View file

@ -52,4 +52,32 @@ public class DateUtilsTest {
assertEquals("1 days, 0 hours, 0 mins, 0 secs", assertEquals("1 days, 0 hours, 0 mins, 0 secs",
DateUtils.formatDuration(DateUtils.MS_PER_DAY + 1)); DateUtils.formatDuration(DateUtils.MS_PER_DAY + 1));
} }
@Test
public void testNormalize() {
long now = System.currentTimeMillis();
long threeHourOffset = 3 * (60 * 60 * 1000);
long future = now + threeHourOffset;
Date nowDate = new Date(now);
Date futureDate = new Date(future);
assertNotEquals(nowDate, futureDate);
Date nowNormalized = DateUtils.normalizeDate(nowDate);
Date futureNormalized = DateUtils.normalizeDate(futureDate);
assertEquals(nowNormalized, futureNormalized);
}
@Test
public void testGetDaysBetween() {
long now = System.currentTimeMillis();
int days = 3;
long threeDaysOffset = days * (24 * 60 * 60 * 1000);
long future = now + threeDaysOffset;
Date nowDate = new Date(now);
Date futureDate = new Date(future);
int daysBetween = DateUtils.getDaysBetween(nowDate, futureDate);
assertEquals(days, daysBetween);
}
} }