I have a text file full of data that I am putting into a Red Black tree, using the date as the key and the rest of the data from that line as the value. The problem is that some of the dates have this format:
"yyyy-MM-dd"
while some of the other dates have this format:
"M/dd/yyyy"
I need a way to compare these two dates, since I am using them as the key in my Red Black tree, so I need a common format. I'm not sure which would be easier for comparison, but I just know that they need to be in the same format. I've read a bit about SimpleDateFormat, but since I'm thinking of reading through the file, having some sort of if statement to determine if the date is in the wrong format, and then formatting it to the one I want, I'm just not sure how to do that with SimpleDateFormat since I've never used it before. Any help would be appreciated!
CodePudding user response:
java.time
The java.util
Date-Time API and their formatting API, SimpleDateFormat
are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Solution using java.time
, the modern Date-Time API: You can specify multiple optional patterns using square brackets inside a DateTimeFormatter
. Parse the date strings into LocalDate
and compare them using LocalDate#isBefore
, LocalDate#isAfter
, LocalDate#isEqual
etc.
Demo:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("[uuuu-MM-dd][M/dd/uuuu]", Locale.ENGLISH);
// Test
Stream.of(
"2021-11-09",
"11/09/2021",
"5/09/2021"
).forEach(s -> System.out.println(LocalDate.parse(s, dtf)));
}
}
Output:
2021-11-09
2021-11-09
2021-05-09
Learn more about the modern Date-Time API from Trail: Date Time.
* If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8 APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time
. Check this answer and this answer to learn how to use java.time
API with JDBC.
CodePudding user response:
java.time
I recommend that you use java.time, the modern Java date and time API, for your date work.
If you are reading data from a text file, as soon as possible parse your date strings into LocalDate
objects and store those in your red-black tree. For parsing strings in your two formats, if you don’t know in advance which format you get, the following method handles both simply by testing whether the string contains a slash or not.
private static final DateTimeFormatter DATE_FORMATTER
= DateTimeFormatter.ofPattern("M/d/y", Locale.ROOT);
/** Parses yyyy-MM-dd or M/d/yyyy */
private static LocalDate parseDateString(String dateString) {
if (dateString.contains("/")) {
return LocalDate.parse(dateString, DATE_FORMATTER);
} else {
return LocalDate.parse(dateString, DateTimeFormatter.ISO_LOCAL_DATE);
}
}
Let’s try it out:
System.out.println(parseDateString("2023-11-20"));
System.out.println(parseDateString("9/18/2019"));
Output:
2023-11-20 2019-09-18
Comparison
LocalDate
implements comparable, so you can compare them using compareTo()
. For a simple demonstration not involving any tree:
LocalDate dateFromIso = parseDateString("2023-11-20");
LocalDate dateFromSlashFormat = parseDateString("9/18/2019");
LocalDate[] dates = { dateFromIso, dateFromSlashFormat };
System.out.println("Before sort: " Arrays.toString(dates));
Arrays.sort(dates);
System.out.println("After sort: " Arrays.toString(dates));
Before sort: [2023-11-20, 2019-09-18] After sort: [2019-09-18, 2023-11-20]
Tutorial link
Oracle tutorial: Date Time explaining how to use java.time.
CodePudding user response:
Personally, I had dealing with date/time values that are String
(or numerically) based. Java (now) has a nice date/time API and we might as well take advantage of it where ever possible (IMHO)
Since you have two formats which are relatively easy to distinguish (either they use /
or -
), it would be a simple matter to parse them, for example...
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
DateTimeFormatter yearMonthDayFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter monthDayYearFormatter = DateTimeFormatter.ofPattern("d/MM/yyyy");
String yearMonthDayValue = "2020-10-10";
String monthDayYearValue = "10/10/2020";
List<String> values = new ArrayList<>();
values.add("2020-10-10");
values.add("10/10/2020");
for (String value : values) {
LocalDate dateValue = null;
if (value.contains("-")) {
dateValue = LocalDate.parse(value, yearMonthDayFormatter);
} else if (value.contains("/")) {
dateValue = LocalDate.parse(value, monthDayYearFormatter);
} else {
System.err.println("Bad format [" value "]");
}
if (dateValue != null) {
// Deal with it
}
}
}
}
I would suggest having a look at the Date/Time trail for more details
CodePudding user response:
Another possibility to complement MadProgrammer's answer would be just delegating the distinction between date formats to the parser itself with exception handling.
Something like defining an array of possible formats (in your case for now just two):
private final DateTimeFormatter[] formats = {
DateTimeFormatter.ofPattern("yyyy-MM-dd"),
DateTimeFormatter.ofPattern("d/MM/yyyy")
};
And creating a method to normalize a "raw" date read in input:
String normalize(String dateRaw) {
if (dateRaw == null) {
throw new IllegalArgumentException("Null date");
}
LocalDate standardized = null;
for (DateTimeFormatter fmt : formats) {
try {
standardized = LocalDate.parse(dateRaw, fmt);
break;
} catch (final DateTimeParseException e) {
// ignore or log if you need to
}
}
if (standardized == null) {
// do something about it, parse failed, invalid date
}
return standardized.toString();
}