Java - 以分钟计算差异
Java - Count Difference in minutes
- 我必须计算这两个日期之间的分钟差,但日期重叠。
- 我有两个日期范围:EventStart、EventEnd
- 我之前写过一个 SQL 查询(见下文),它工作得很好,但它真的很慢,所以我想在 Java (resultSet)
中处理它
这是我从 SQL 服务器获得的 JSON:
https://pastebin.com/raw/xhCnXynA
这是我正在运行的 SQL 脚本:
DECLARE @T TABLE(ID INT,FromDate DATETIME, ToDate DATETIME)
INSERT INTO @T(ID,FromDate,ToDate)
SELECT 1,'20090801','20090803' UNION ALL
SELECT 2,'20090802','20090809' UNION ALL
SELECT 3,'20090805','20090806' UNION ALL
SELECT 4,'20090812','20090813' UNION ALL
SELECT 5,'20090811','20090812' UNION ALL
SELECT 6,'20090802','20090802'
SELECT ROW_NUMBER() OVER(ORDER BY s1.FromDate) AS ID,
s1.FromDate,
MIN(t1.ToDate) AS ToDate
FROM @T s1
INNER JOIN @T t1 ON s1.FromDate <= t1.ToDate
AND NOT EXISTS(SELECT * FROM @T t2
WHERE t1.ToDate >= t2.FromDate
AND t1.ToDate < t2.ToDate)
WHERE NOT EXISTS(SELECT * FROM @T s2
WHERE s1.FromDate > s2.FromDate
AND s1.FromDate <= s2.ToDate)
GROUP BY s1.FromDate
ORDER BY s1.FromDate
结果:
我的Java代码:
//Date Format
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Integer downTime;
while (rs.next()) {
//Parse to Date
eventStart = formatter.parse(rs.getString("EventStart"));
eventEnd = formatter.parse(rs.getString("EventEnd"));
if (eventStart.after(eventEnd)){
//How should I do this?
}
else{
//How should I do this?
}
//I have to count here the difference between the dates in minutes
}
计算两个日期之间的分钟差
最好使用新 Java Date/Time API 中的 java.time.format.DateTimeFormatter
和 java.time.LocalDateTime
而不是 SimpleDateFormat
和 Date
:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
LocalDateTime eventStart = LocalDateTime.parse("2019-10-09 01:24:05.0", formatter);
LocalDateTime eventEnd = LocalDateTime.parse("2019-10-09 01:35:14.0", formatter);
Duration duration;
if (eventStart.isBefore(eventEnd)) {
duration = Duration.between(eventStart, eventEnd);
} else {
duration = Duration.between(eventEnd, eventStart);
}
long minutes = duration.toMinutes();
System.out.println("" + minutes + " minute(s)");
结果是:11 minute(s)
.
合并所有重叠的日期范围
要合并所有重叠的日期范围,请考虑以下方法。
创建一个 class 以使用方法 isOverlappingWith
、mergeWith
、toMinutes
表示日期范围并覆盖 equals
和 hashCode
。
private static class DateRange {
private final LocalDateTime startDate;
private final LocalDateTime endDate;
public DateRange(LocalDateTime startDate, LocalDateTime endDate) {
this.startDate = startDate;
this.endDate = endDate;
}
public boolean isOverlappingWith(DateRange other) {
return !startDate.isAfter(other.endDate) && !endDate.isBefore(other.startDate);
}
public DateRange mergeWith(DateRange other) {
return new DateRange(
startDate.isBefore(other.startDate) ? startDate : other.startDate,
endDate.isAfter(other.endDate) ? endDate : other.endDate);
}
public long toMinutes() {
return Duration.between(startDate, endDate).toMinutes();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DateRange dateRange = (DateRange) o;
return Objects.equals(startDate, dateRange.startDate) &&
Objects.equals(endDate, dateRange.endDate);
}
@Override
public int hashCode() {
return Objects.hash(startDate, endDate);
}
@Override
public String toString() {
return "DateRange{" +
"startDate=" + startDate +
", endDate=" + endDate +
'}';
}
}
遍历所有日期范围并尝试合并它们。要跟踪重复项,需要额外的 HashSet
。这个想法是尝试将每个日期范围与列表中的下一个范围合并。如果至少有一个合并,则删除原始日期范围。如果列表不包含生成的合并日期范围,则将其附加到列表中。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
List<List<String>> rawDateRanges = List.of(
List.of("2009-08-01 00:00:00.0", "2009-08-03 00:00:00.0"),
List.of("2009-08-05 00:00:00.0", "2009-08-06 00:00:00.0"),
List.of("2009-08-02 00:00:00.0", "2009-08-09 00:00:00.0"),
List.of("2009-08-12 00:00:00.0", "2009-08-13 00:00:00.0"),
List.of("2009-08-11 00:00:00.0", "2009-08-12 00:00:00.0"),
List.of("2009-08-02 00:00:00.0", "2009-08-02 00:00:00.0"));
List<DateRange> dateRanges = new ArrayList<>();
for (List<String> rawDateRange : rawDateRanges) { //Replace with while (rs.next()) { ... }
LocalDateTime fromDate = LocalDateTime.parse(rawDateRange.get(0), formatter);
LocalDateTime toDate = LocalDateTime.parse(rawDateRange.get(1), formatter);
dateRanges.add(new DateRange(fromDate, toDate));
}
Set<DateRange> mergedDateRanges = new HashSet<>();
for (int i = 0; i < dateRanges.size(); i++) {
DateRange dateRange = dateRanges.get(i);
boolean merged = false;
for (int j = i + 1; j < dateRanges.size(); j++) {
DateRange otherDateRange = dateRanges.get(j);
if (dateRange.isOverlappingWith(otherDateRange)) {
dateRange = dateRange.mergeWith(otherDateRange);
merged = true;
}
}
if (merged) {
dateRanges.remove(i--);
if (mergedDateRanges.add(dateRange)) {
dateRanges.add(dateRange);
}
}
}
List<Long> minutes = dateRanges.stream()
.peek(System.out::println)
.map(DateRange::toMinutes) //Convert to minutes
.collect(toList());
System.out.println(minutes);
输出:
DateRange{startDate=2009-08-01T00:00, endDate=2009-08-09T00:00}
DateRange{startDate=2009-08-11T00:00, endDate=2009-08-13T00:00}
[11520, 2880]
- 我必须计算这两个日期之间的分钟差,但日期重叠。
- 我有两个日期范围:EventStart、EventEnd
- 我之前写过一个 SQL 查询(见下文),它工作得很好,但它真的很慢,所以我想在 Java (resultSet) 中处理它
这是我从 SQL 服务器获得的 JSON:
https://pastebin.com/raw/xhCnXynA
这是我正在运行的 SQL 脚本:
DECLARE @T TABLE(ID INT,FromDate DATETIME, ToDate DATETIME)
INSERT INTO @T(ID,FromDate,ToDate)
SELECT 1,'20090801','20090803' UNION ALL
SELECT 2,'20090802','20090809' UNION ALL
SELECT 3,'20090805','20090806' UNION ALL
SELECT 4,'20090812','20090813' UNION ALL
SELECT 5,'20090811','20090812' UNION ALL
SELECT 6,'20090802','20090802'
SELECT ROW_NUMBER() OVER(ORDER BY s1.FromDate) AS ID,
s1.FromDate,
MIN(t1.ToDate) AS ToDate
FROM @T s1
INNER JOIN @T t1 ON s1.FromDate <= t1.ToDate
AND NOT EXISTS(SELECT * FROM @T t2
WHERE t1.ToDate >= t2.FromDate
AND t1.ToDate < t2.ToDate)
WHERE NOT EXISTS(SELECT * FROM @T s2
WHERE s1.FromDate > s2.FromDate
AND s1.FromDate <= s2.ToDate)
GROUP BY s1.FromDate
ORDER BY s1.FromDate
结果:
我的Java代码:
//Date Format
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Integer downTime;
while (rs.next()) {
//Parse to Date
eventStart = formatter.parse(rs.getString("EventStart"));
eventEnd = formatter.parse(rs.getString("EventEnd"));
if (eventStart.after(eventEnd)){
//How should I do this?
}
else{
//How should I do this?
}
//I have to count here the difference between the dates in minutes
}
计算两个日期之间的分钟差
最好使用新 Java Date/Time API 中的 java.time.format.DateTimeFormatter
和 java.time.LocalDateTime
而不是 SimpleDateFormat
和 Date
:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
LocalDateTime eventStart = LocalDateTime.parse("2019-10-09 01:24:05.0", formatter);
LocalDateTime eventEnd = LocalDateTime.parse("2019-10-09 01:35:14.0", formatter);
Duration duration;
if (eventStart.isBefore(eventEnd)) {
duration = Duration.between(eventStart, eventEnd);
} else {
duration = Duration.between(eventEnd, eventStart);
}
long minutes = duration.toMinutes();
System.out.println("" + minutes + " minute(s)");
结果是:11 minute(s)
.
合并所有重叠的日期范围
要合并所有重叠的日期范围,请考虑以下方法。
创建一个 class 以使用方法 isOverlappingWith
、mergeWith
、toMinutes
表示日期范围并覆盖 equals
和 hashCode
。
private static class DateRange {
private final LocalDateTime startDate;
private final LocalDateTime endDate;
public DateRange(LocalDateTime startDate, LocalDateTime endDate) {
this.startDate = startDate;
this.endDate = endDate;
}
public boolean isOverlappingWith(DateRange other) {
return !startDate.isAfter(other.endDate) && !endDate.isBefore(other.startDate);
}
public DateRange mergeWith(DateRange other) {
return new DateRange(
startDate.isBefore(other.startDate) ? startDate : other.startDate,
endDate.isAfter(other.endDate) ? endDate : other.endDate);
}
public long toMinutes() {
return Duration.between(startDate, endDate).toMinutes();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DateRange dateRange = (DateRange) o;
return Objects.equals(startDate, dateRange.startDate) &&
Objects.equals(endDate, dateRange.endDate);
}
@Override
public int hashCode() {
return Objects.hash(startDate, endDate);
}
@Override
public String toString() {
return "DateRange{" +
"startDate=" + startDate +
", endDate=" + endDate +
'}';
}
}
遍历所有日期范围并尝试合并它们。要跟踪重复项,需要额外的 HashSet
。这个想法是尝试将每个日期范围与列表中的下一个范围合并。如果至少有一个合并,则删除原始日期范围。如果列表不包含生成的合并日期范围,则将其附加到列表中。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
List<List<String>> rawDateRanges = List.of(
List.of("2009-08-01 00:00:00.0", "2009-08-03 00:00:00.0"),
List.of("2009-08-05 00:00:00.0", "2009-08-06 00:00:00.0"),
List.of("2009-08-02 00:00:00.0", "2009-08-09 00:00:00.0"),
List.of("2009-08-12 00:00:00.0", "2009-08-13 00:00:00.0"),
List.of("2009-08-11 00:00:00.0", "2009-08-12 00:00:00.0"),
List.of("2009-08-02 00:00:00.0", "2009-08-02 00:00:00.0"));
List<DateRange> dateRanges = new ArrayList<>();
for (List<String> rawDateRange : rawDateRanges) { //Replace with while (rs.next()) { ... }
LocalDateTime fromDate = LocalDateTime.parse(rawDateRange.get(0), formatter);
LocalDateTime toDate = LocalDateTime.parse(rawDateRange.get(1), formatter);
dateRanges.add(new DateRange(fromDate, toDate));
}
Set<DateRange> mergedDateRanges = new HashSet<>();
for (int i = 0; i < dateRanges.size(); i++) {
DateRange dateRange = dateRanges.get(i);
boolean merged = false;
for (int j = i + 1; j < dateRanges.size(); j++) {
DateRange otherDateRange = dateRanges.get(j);
if (dateRange.isOverlappingWith(otherDateRange)) {
dateRange = dateRange.mergeWith(otherDateRange);
merged = true;
}
}
if (merged) {
dateRanges.remove(i--);
if (mergedDateRanges.add(dateRange)) {
dateRanges.add(dateRange);
}
}
}
List<Long> minutes = dateRanges.stream()
.peek(System.out::println)
.map(DateRange::toMinutes) //Convert to minutes
.collect(toList());
System.out.println(minutes);
输出:
DateRange{startDate=2009-08-01T00:00, endDate=2009-08-09T00:00}
DateRange{startDate=2009-08-11T00:00, endDate=2009-08-13T00:00}
[11520, 2880]