繁体   English   中英

Java 中的时间计算问题

[英]Issue with Time Calculation in Java

在筛选测试中,我被要求编写一个程序来获得一天中可用的最大空闲时间。

例如:

输入: “10:00AM-12:30PM”,“02:00PM-02:45PM”,“09:10AM-09:50AM”
预计 Output: 01:30

这些时间范围可能不按递增顺序排列。

对于这个问题,我尝试在 java 中编写一个小代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.time.Duration;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;

public class TimeDiff {

    public static void main(String[] args) throws NullPointerException {
        String accStr = null;

        System.out.println("Enter day time entries : ");
        try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
            accStr = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        String unQuoted = accStr.replace("\"", "");
        String[] inputSplit = unQuoted.split(",");
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("hh:mma");
        Map<LocalTime, LocalTime> timeMap = new TreeMap<>();
        for (String x : inputSplit) {
            String[] furtherSplit = x.split("-");
            timeMap.put(LocalTime.parse(furtherSplit[0], dateTimeFormatter), LocalTime.parse(furtherSplit[1], dateTimeFormatter));
        }
        Iterator iterator = timeMap.entrySet().iterator();

        List<Long> duration = new ArrayList<Long>();
        LocalTime[][] convertedMaptoArray = new LocalTime[timeMap.size()][2];
        int rowIndex = 0;

        while (iterator.hasNext()) {
            int colIndex = 0;
            Map.Entry pair = (Map.Entry) iterator.next();
            //System.out.println(pair.getKey() + " " + pair.getValue());
            convertedMaptoArray[rowIndex][colIndex] = (LocalTime) pair.getKey();
            convertedMaptoArray[rowIndex][colIndex+1]=(LocalTime)pair.getValue();
            rowIndex++;
        }

        LocalTime previousRecordEndTime = null;
        LocalTime currentRecordStartTime = null;
        for(int i= 0; i<=convertedMaptoArray.length-1;i++)
        {
            currentRecordStartTime = convertedMaptoArray[i][0];
            //System.out.println("current :" +currentRecordStartTime);
            if(i>0){
                previousRecordEndTime = convertedMaptoArray[i-1][1];
                //System.out.println("Previous : " + previousRecordEndTime);
                duration.add(ChronoUnit.MINUTES.between(previousRecordEndTime, currentRecordStartTime));
            }
        }

        System.out.println("Longest duration : " + LocalTime.MIN.plus(Duration.ofMinutes(Collections.max(duration))).toString());

    }
}

我被筛选了,但我对上面的代码有几个问题:

  1. 如何优化这段代码?
  2. 上面的代码是否违反了任何编码规则?
  3. 在 Java 中计算时间应该有什么更好的方法?

请帮忙。 提前致谢。

我认为你正在破坏 KISS(使事情过于复杂),同时混合了 2 个截然不同的职责:解析输入的职责和计算间隔的职责 - 你只对最短的时间感兴趣,因此存储所有内容没有必要。

输入是否假定为通过控制台输入的字符串?

我将其分解为以下方法:

// 01:00AM -> 60
private static int timeStringToMinutesFromMidnight(String time)
// 60 -> 01:00
private static String minutesToHoursAndMinutes(int minutes)
// 11:00AM-11:30AM -> 660 690 added to list
private static void parseInterval(String interval, List<Integer> minutes)

(在之前的编辑中,我有timeStringIntervalToMinutes ,但我误读了问题并且计算了错误的输出)。

您在这里不需要任何复杂的数据结构:一个简单的List可以让您完成所需的一切。 对其进行排序比使用TreeMapTreeSet更容易 - 是的,它们进行自己的排序,但在占用空间和访问速度方面也更重。

完整代码(导入java.util.*java.io.* ):

// 01:00AM -> 60
private static int timeStringToMinutesFromMidnight(String time) {
    int hours = Integer.parseInt(time.substring(0,"hh".length()));
    int minutes = Integer.parseInt(time.substring("hh:".length(), "hh:mm".length()));
    boolean afternoon = time.substring("hh:mm".length()).equalsIgnoreCase("PM");
    if (afternoon && hours != 12) {
        hours += 12;
    }
    return hours * 60 + minutes;
}

// 60 -> 01:00
private static String minutesToHoursAndMinutes(int minutes) {
    int hours = minutes / 60;
    minutes = minutes % 60;
    return String.format("%02d:%02d", hours, minutes);
}

// 11:00AM-11:30AM -> 660 690 added to list
private static void parseInterval(String interval, List<Integer> minutes) {
    String[] parts = interval.split("-");
    int start = timeStringToMinutesFromMidnight(parts[0]);
    int end = timeStringToMinutesFromMidnight(parts[1]);
    if (end < start) {
        throw new IllegalArgumentException("interval " + interval + " has end<start");
    }
    minutes.add(start);
    minutes.add(end);
} 

// Input: "10:00AM-12:30PM","02:00PM-02:45PM","09:10AM-09:50AM"
// Expected Output: 01:30
public static void main(String ... args) {

    List<Integer> endpoints = new ArrayList<>();
    try (Scanner sc = new Scanner(System.in).useDelimiter("[,\"]+")) {
        while (sc.hasNext()) {
            parseInterval(sc.next(), endpoints);
        }
    }
    if (endpoints.isEmpty()) {
        System.out.println("No intervals found");
        return;
    }

    // sort the endpoints (assuming that no intervals overlap, intervals will not be broken)
    Collections.sort(endpoints);

    int largest = -1;
    for (int i=1; i<endpoints.size()-1; i+=2) {
        largest = Math.max(largest,  endpoints.get(i+1) - endpoints.get(i));
    }        
    System.out.println(minutesToHoursAndMinutes(largest));
}

我建议:

  • 不要将Map用于您的条目。 使用一对 class 或定义一个TimeRange class 可以容纳两个LocalTime对象。 然后收集这些。
  • 即使你想使用Map ,也不要使用原始的Map.Entry 参数化为Map.Entry<LocalTIme, LocalTime> 同样参数化你的迭代器。 (另一方面, new ArrayList<Long>()中的类型参数是多余的;只是new ArrayList<>()是常规的。)
  • 不要将Long用于持续时间。 只需在整个过程中使用Duration class。 使用其compareTo方法进行比较。
  • 我首先将字符串拆分为时间范围,然后仅删除前导引号和尾随引号。 这提供了一定程度的输入验证。
  • 为了找到最大免费持续时间,我会使用内置的 max 方法,例如双参数Collections.max() 我会传递从Arrays.asList()获得的列表,或者甚至更好,避免 arrays 并将持续时间专门保留在列表中。 然后当然是适当的Comparator实现。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM