有没有更好的比较日期的方法
Is there a better way of comparing dates
我正在尝试比较两个日期。
日期作为字符串从数据库导入,可能为空也可能不为空
这是我的代码
private String compareDates(String date1, String date2)
{
String earliestDate = null;
// date2 is null and date1 is null
// earliest = “not seen yet”
if (date2 == null && date1 == null)
{
earliestDate = "not seen yet";
}
// date2 is null and date1 is not null
// earliest = date1
if (date2 == null && date1 != null)
{
earliestDate = date1;
}
// date2 is not null and date1 is null
// earliest = date2
if (date2 != null && date1 == null)
{
earliestDate = date2;
}
// date2 is not null and date1 is not null
// compare dates
if (date2 != null && date1 != null)
{
LocalDate LDdate1 = LocalDate.parse(date1);
LocalDate LDdate2 = LocalDate.parse(date2);
if (LDdate1.isBefore(LDdate2) || LDdate1.isEqual(LDdate2))
{
earliestDate = LDdate1.toString();
}
else
{
earliestDate = LDdate2.toString();
}
}
return earliestDate;
}
这段代码给了我正确的输出,这是最早的日期,如果两个日期都为空,则为“尚未看到”,但我想知道是否有更好/更有效的做事方式。
我认为使用 switch 语句是一种选择,但如果换一种方式会更好吗?
数据库中的数据仅包含大约 200 个日期,因此它处理的数据不多,只是我有兴趣编写更好的代码
下面的怎么样?
private String compareDates(String date1, String date2) {
String earliestDate;
if (date1 == null) {
if (date2 == null) {
earliestDate = "not seen yet";
}
else {
earliestDate = date2;
}
}
else {
if (date2 == null) {
earliestDate = date1;
}
else {
LocalDate LDdate1 = LocalDate.parse(date1);
LocalDate LDdate2 = LocalDate.parse(date2);
if (LDdate1.isAfter(LDdate2)) {
earliestDate = date2;
}
else {
earliestDate = date1;
}
}
}
return earliestDate;
}
如果条件如下,您可以减少一个:
private String compareDates(String date1, String date2) {
String earliestDate = "not seen yet";
if (!StringUtils.isEmpty(date2) && !StringUtils.isEmpty(date1)) {
LocalDate LDdate1 = LocalDate.parse(date1);
LocalDate LDdate2 = LocalDate.parse(date2);
if (LDdate1.isBefore(LDdate2) || LDdate1.isEqual(LDdate2)) {
earliestDate = LDdate1.toString();
}
else {
earliestDate = LDdate2.toString();
}
} else if (!StringUtils.isEmpty(date2) && StringUtils.isEmpty(date1)) {
earliestDate = LDdate2;
} else if (StringUtils.isEmpty(date2) && !StringUtils.isEmpty(date1)) {
earliestDate = LDdate1;
}
return earliestDate;
}
您可以使用自定义 Comparator
,它允许以 声明性 方式指定比较逻辑:
private String compareDates(String date1, String date2) {
Comparator<String> c = Comparator.nullsLast(
Comparator.comparing(LocalDate::parse));
int result = c.compare(date1, date2);
return result == 0 && date1 == null ?
"not seen yet" :
result <= 0 ?
date1 :
date2;
}
除了一堆看起来相似的 if 语句之外,还有一些其他选项。
Comparator
if (date1 == null && date2 == null) {
return "not seen yet";
}
Comparator<String> c = Comparator.nullsLast((String a, String b) -> LocalDate.parse(a).compareTo(LocalDate.parse(b)));
return c.compare(date1, date2) <= 0 ? date1 : date2;
Stream::reduce
使用 Comparator
return Stream.of(date1, date2)
.filter(Objects::nonNull)
.reduce((a, b) -> LocalDate.parse(a).compareTo(LocalDate.parse(b)) <= 0 ? a : b)
.orElse("not seen yet");
对我来说,这两个选项都比您现在的可读性更好,但我会选择选项 1。人们可能会发现使用流有点矫枉过正,这在某种程度上是正确的。
如果日期采用标准本地格式并按 YYYY MM DD 排序,例如
"2018-01-24"
为什么要费心解析呢?只需进行字符串比较。大约快 100 倍,也更容易。
public static String compareDatesStr(String date1, String date2) {
if (date1 == null)
if (date2 == null)
return "not seen yet";
else
return date2;
else if (date2 == null)
return date1;
else
return date1.compareTo(date2) > 0 ? date2 : date1;
}
一些非科学的性能比较:
private static String compareDatesParse(String date1, String date2) {
String earliestDate;
if (date1 == null) {
if (date2 == null) {
earliestDate = "not seen yet";
}
else {
earliestDate = date2;
}
}
else {
if (date2 == null) {
earliestDate = date1;
}
else {
LocalDate LDdate1 = LocalDate.parse(date1);
LocalDate LDdate2 = LocalDate.parse(date2);
if (LDdate1.isAfter(LDdate2)) {
earliestDate = date2;
}
else {
earliestDate = date1;
}
}
}
return earliestDate;
}
public static void testDateComp(){
String[] dates = {"2020-10-30", "2020-10-29", "1990-10-30", "2021-06-01", null};
String result = null;
int loops = 400000;
long start, end = 0;
// System.out.println("Runs: " + (dates.length*dates.length*loops));
start = System.currentTimeMillis();
for (int i = 0; i < loops; i++) {
for (String date1:dates) {
for (String date2:dates) {
result = compareDatesStr(date1, date2);
}
}
}
end = System.currentTimeMillis();
System.out.println("Runtime String: " + (end - start)+ "ms");
start = System.currentTimeMillis();
for (int i = 0; i < loops; i++) {
for (String date1:dates) {
for (String date2:dates) {
result = compareDatesParse(date1, date2);
}
}
}
end = System.currentTimeMillis();
System.out.println("Runtime Parsing: " + (end - start) + "ms");
}
10MM 方法执行次数:
Runtime String: 61ms
Runtime Parsing: 7361ms
The dates are imported from a database as strings …
第一点:不要那样做。从数据库中以 LocalDate
对象的形式获取日期,并在程序中这样处理它们。有关如何从 SQL 数据库中获取 LocalDate
,请参阅底部的 link。
接下来,我将使用流管道来查找较早的管道:
// Some example dates
LocalDate date1 = null;
LocalDate date2 = LocalDate.of(2020, Month.OCTOBER, 24);
String earlierDate = Stream.of(date1, date2)
.filter(Objects::nonNull)
.min(LocalDate::compareTo)
.map(LocalDate::toString)
.orElse("Not seen yet");
System.out.println(earlierDate);
输出:
2020-10-24
Link: 问题
我正在尝试比较两个日期。 日期作为字符串从数据库导入,可能为空也可能不为空
这是我的代码
private String compareDates(String date1, String date2)
{
String earliestDate = null;
// date2 is null and date1 is null
// earliest = “not seen yet”
if (date2 == null && date1 == null)
{
earliestDate = "not seen yet";
}
// date2 is null and date1 is not null
// earliest = date1
if (date2 == null && date1 != null)
{
earliestDate = date1;
}
// date2 is not null and date1 is null
// earliest = date2
if (date2 != null && date1 == null)
{
earliestDate = date2;
}
// date2 is not null and date1 is not null
// compare dates
if (date2 != null && date1 != null)
{
LocalDate LDdate1 = LocalDate.parse(date1);
LocalDate LDdate2 = LocalDate.parse(date2);
if (LDdate1.isBefore(LDdate2) || LDdate1.isEqual(LDdate2))
{
earliestDate = LDdate1.toString();
}
else
{
earliestDate = LDdate2.toString();
}
}
return earliestDate;
}
这段代码给了我正确的输出,这是最早的日期,如果两个日期都为空,则为“尚未看到”,但我想知道是否有更好/更有效的做事方式。
我认为使用 switch 语句是一种选择,但如果换一种方式会更好吗?
数据库中的数据仅包含大约 200 个日期,因此它处理的数据不多,只是我有兴趣编写更好的代码
下面的怎么样?
private String compareDates(String date1, String date2) {
String earliestDate;
if (date1 == null) {
if (date2 == null) {
earliestDate = "not seen yet";
}
else {
earliestDate = date2;
}
}
else {
if (date2 == null) {
earliestDate = date1;
}
else {
LocalDate LDdate1 = LocalDate.parse(date1);
LocalDate LDdate2 = LocalDate.parse(date2);
if (LDdate1.isAfter(LDdate2)) {
earliestDate = date2;
}
else {
earliestDate = date1;
}
}
}
return earliestDate;
}
如果条件如下,您可以减少一个:
private String compareDates(String date1, String date2) {
String earliestDate = "not seen yet";
if (!StringUtils.isEmpty(date2) && !StringUtils.isEmpty(date1)) {
LocalDate LDdate1 = LocalDate.parse(date1);
LocalDate LDdate2 = LocalDate.parse(date2);
if (LDdate1.isBefore(LDdate2) || LDdate1.isEqual(LDdate2)) {
earliestDate = LDdate1.toString();
}
else {
earliestDate = LDdate2.toString();
}
} else if (!StringUtils.isEmpty(date2) && StringUtils.isEmpty(date1)) {
earliestDate = LDdate2;
} else if (StringUtils.isEmpty(date2) && !StringUtils.isEmpty(date1)) {
earliestDate = LDdate1;
}
return earliestDate;
}
您可以使用自定义 Comparator
,它允许以 声明性 方式指定比较逻辑:
private String compareDates(String date1, String date2) {
Comparator<String> c = Comparator.nullsLast(
Comparator.comparing(LocalDate::parse));
int result = c.compare(date1, date2);
return result == 0 && date1 == null ?
"not seen yet" :
result <= 0 ?
date1 :
date2;
}
除了一堆看起来相似的 if 语句之外,还有一些其他选项。
Comparator
if (date1 == null && date2 == null) { return "not seen yet"; } Comparator<String> c = Comparator.nullsLast((String a, String b) -> LocalDate.parse(a).compareTo(LocalDate.parse(b))); return c.compare(date1, date2) <= 0 ? date1 : date2;
Stream::reduce
使用Comparator
return Stream.of(date1, date2) .filter(Objects::nonNull) .reduce((a, b) -> LocalDate.parse(a).compareTo(LocalDate.parse(b)) <= 0 ? a : b) .orElse("not seen yet");
对我来说,这两个选项都比您现在的可读性更好,但我会选择选项 1。人们可能会发现使用流有点矫枉过正,这在某种程度上是正确的。
如果日期采用标准本地格式并按 YYYY MM DD 排序,例如
"2018-01-24"
为什么要费心解析呢?只需进行字符串比较。大约快 100 倍,也更容易。
public static String compareDatesStr(String date1, String date2) {
if (date1 == null)
if (date2 == null)
return "not seen yet";
else
return date2;
else if (date2 == null)
return date1;
else
return date1.compareTo(date2) > 0 ? date2 : date1;
}
一些非科学的性能比较:
private static String compareDatesParse(String date1, String date2) {
String earliestDate;
if (date1 == null) {
if (date2 == null) {
earliestDate = "not seen yet";
}
else {
earliestDate = date2;
}
}
else {
if (date2 == null) {
earliestDate = date1;
}
else {
LocalDate LDdate1 = LocalDate.parse(date1);
LocalDate LDdate2 = LocalDate.parse(date2);
if (LDdate1.isAfter(LDdate2)) {
earliestDate = date2;
}
else {
earliestDate = date1;
}
}
}
return earliestDate;
}
public static void testDateComp(){
String[] dates = {"2020-10-30", "2020-10-29", "1990-10-30", "2021-06-01", null};
String result = null;
int loops = 400000;
long start, end = 0;
// System.out.println("Runs: " + (dates.length*dates.length*loops));
start = System.currentTimeMillis();
for (int i = 0; i < loops; i++) {
for (String date1:dates) {
for (String date2:dates) {
result = compareDatesStr(date1, date2);
}
}
}
end = System.currentTimeMillis();
System.out.println("Runtime String: " + (end - start)+ "ms");
start = System.currentTimeMillis();
for (int i = 0; i < loops; i++) {
for (String date1:dates) {
for (String date2:dates) {
result = compareDatesParse(date1, date2);
}
}
}
end = System.currentTimeMillis();
System.out.println("Runtime Parsing: " + (end - start) + "ms");
}
10MM 方法执行次数:
Runtime String: 61ms
Runtime Parsing: 7361ms
The dates are imported from a database as strings …
第一点:不要那样做。从数据库中以 LocalDate
对象的形式获取日期,并在程序中这样处理它们。有关如何从 SQL 数据库中获取 LocalDate
,请参阅底部的 link。
接下来,我将使用流管道来查找较早的管道:
// Some example dates
LocalDate date1 = null;
LocalDate date2 = LocalDate.of(2020, Month.OCTOBER, 24);
String earlierDate = Stream.of(date1, date2)
.filter(Objects::nonNull)
.min(LocalDate::compareTo)
.map(LocalDate::toString)
.orElse("Not seen yet");
System.out.println(earlierDate);
输出:
2020-10-24
Link: 问题