每15分钟Java日期时间比较

时间:2015-05-20 00:08:41

标签: java date datetime

我有一个带有时间戳的csv记录,或者每隔5分钟:

- 2015/05/19 16:15:00
- 2015/05/19 16:20:00
- 2015/05/19 16:35:00
- 2015/05/19 16:10:00
- 2015/05/19 16:55:00

我使用数组来比较每条记录的日期是否在15分钟内:

ArrayList<String> per15Min = new ArrayList<String>() {{
    add("00,15");
    add("15,30");
    add("30,45");
    add("45,00");
}};

我所做的是阅读每条记录,根据&#34;,&#34;提取日期:

private SimpleDateFormat csvDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
private SimpleDateFormat fileDateFormat = new SimpleDateFormat("yyyyMMddHHmm");

// Loop thru each record
while ((perLine = br.readLine()) != null) {

    // Store date per record in a string
    String[] perColumn = perLine.split(",", -1);
    String date = perColumn[0];

    // Convert record date to yyyyMMddHHmm
    Date subDateP = csvDateFormat.parse(csvDate);
    String subDateF = fileDateFormat.format(subDateP);

    // Extract the date without the day (dd)
    String subDate = subDateF.substring(0,10);

    for (int j = 0 ; j < per15Min.size() ; j++) {
        String[] s = per15Min.get(j).split(",", -1);
        String m1 = s[0];
        String m2 = s[1];

        // All dates are in a yyyyMMddHHmm format
        Date before = fileDateFormat.parse(subDate + m1);
        Date after = fileDateFormat.parse(subDate + m2);
        Date csvRd = fileDateFormat.parse(date);

        System.out.println("DATE " + before + " : " + after + " : " + csvRd);

        // Having problems doing date comparison            
        if ((before.compareTo(csvRd) >= 0) && (csvRd.compareTo(after) < 0)) {
            System.out.println("DATE HERE" + before + " : " + after + " : " + csvRd);
        }


    }
}

正如您从sysout中看到的那样,它似乎不起作用:

DATE HEREWed May 20 07:30:00 SGT 2015 : Wed May 20 07:45:00 SGT 2015 : Wed May 20 07:30:00 SGT 2015
DATE HEREWed May 20 07:30:00 SGT 2015 : Wed May 20 07:45:00 SGT 2015 : Wed May 20 07:25:00 SGT 2015
DATE HEREWed May 20 07:30:00 SGT 2015 : Wed May 20 07:45:00 SGT 2015 : Wed May 20 07:20:00 SGT 2015
DATE HEREWed May 20 07:30:00 SGT 2015 : Wed May 20 07:45:00 SGT 2015 : Wed May 20 07:15:00 SGT 2015
DATE HEREWed May 20 07:30:00 SGT 2015 : Wed May 20 07:45:00 SGT 2015 : Wed May 20 07:10:00 SGT 2015

我需要的是如果时间戳(每5分钟)在15分钟数组内,它将进入条件:

00-10 minutes must enter at 00,15
15-25 minutes must enter at 15,30
30-40 minutes must enter at 30,45
45-55 minutes must enter at 45,00

任何人都知道if条件有什么问题吗?

3 个答案:

答案 0 :(得分:2)

每当您需要处理日期/时间信息时,您应该使用适当的API,在您的情况下,您可以使用DateCalendar,但最好使用Java如果可以,可以使用8&#39的时间API,或者Joda-Time,因为交互比Calendar更简单

String日期值转换为Date s或(更好)LocalDateTime值并使用其比较方法

  • Date#beforeDate#afterDate#equals
  • LocalDateTime#isBeforeLocalDateTime#isAfterLocalDateTime#equals

例如......

List<String> listOfDateValues = new ArrayList<>(25);
listOfDateValues.addAll(Arrays.asList(
                new String[]{"2015/05/19 16:10:00",
                    "2015/05/19 16:00:00",
                    "2015/05/19 16:05:00",
                    "2015/05/19 16:10:00",
                    "2015/05/19 16:15:00",
                    "2015/05/19 16:20:00",
                    "2015/05/19 16:25:00",
                    "2015/05/19 16:30:00",
                    "2015/05/19 16:35:00",
                    "2015/05/19 16:40:00",
                    "2015/05/19 16:45:00",
                    "2015/05/19 16:50:00",
                    "2015/05/19 16:55:00",
                    "2015/05/19 16:25:00"}));

List<String> per15Min = new ArrayList<>(
                Arrays.asList(
                                new String[]{
                                    "00,15",
                                    "16,30",
                                    "31,45",
                                    "46,59" //??
                                }
                )
);

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
Map<String, List<String>> mapGroups = new HashMap<>();
for (String dateValue : listOfDateValues) {

    LocalDateTime ldt = LocalDateTime.parse(dateValue, formatter);
    for (String range : per15Min) {
        String[] split = range.split(",");
        LocalDateTime startRange = ldt.withMinute(Integer.parseInt(split[0])).withSecond(0).withNano(0);
        LocalDateTime endRange = ldt.withMinute(Integer.parseInt(split[1])).withSecond(59).withNano(999999999);
        if ((ldt.equals(startRange) || ldt.isAfter(startRange))
                        && (ldt.equals(endRange) || ldt.isBefore(endRange))) {
            List<String> group = mapGroups.get(range);
            if (group == null) {
                group = new ArrayList<String>(25);
                mapGroups.put(range, group);
            }
            group.add(dateValue);
        }
    }

}

for (String range : per15Min) {
    List<String> group = mapGroups.get(range);
    System.out.println(range);
    for (String dateValue : group) {
        System.out.println(" -> " + dateValue);
    }
}

哪些输出......

00,15
 -> 2015/05/19 16:10:00
 -> 2015/05/19 16:00:00
 -> 2015/05/19 16:05:00
 -> 2015/05/19 16:10:00
 -> 2015/05/19 16:15:00
16,30
 -> 2015/05/19 16:20:00
 -> 2015/05/19 16:25:00
 -> 2015/05/19 16:30:00
 -> 2015/05/19 16:25:00
31,45
 -> 2015/05/19 16:35:00
 -> 2015/05/19 16:40:00
 -> 2015/05/19 16:45:00
46,59
 -> 2015/05/19 16:50:00
 -> 2015/05/19 16:55:00

注意,我已经修改过你的游侠,因此00-1515-30的范围是没有意义的...... xx:15.00的时间在哪里?进入两组?

答案 1 :(得分:2)

您提供的代码显示了很多难闻的气味(或反模式):计算机科学家通过经验发现的模式会导致很多问题。

最成问题的是你依赖字符串格式化和解析。

  

仅使用 text 的字符串,而不是元组 Date 等各种数据的中间表示 >等等

特别是对于像Date这样的文化依赖概念,这可能导致完全混乱。例如,有些文化可能不会使用阿拉伯数字(如12)来写日期,但例如使用罗马数字(如XII)。或者在某个时间点,年份将不再具有四位数的可表示,或者一个用时区12:15:57 UTC+01解析日期,但在格式化和解析期间时区丢失。一般来说,使用字符串处理进行数据处理是一个坏主意,只有在数据是text / names / strings /...

时才这样做。

接下来,您似乎存储了15的倍数,这有点无用。它会减慢这个过程。

  

不要明确存储倍数等,只使用暴力方法(如果绝对必要,你可以枚举元素。

在这个答案中,我提出了两种方法:dateFloor(Date d, int m)dateCeil(Date d, int m)。您可以传递分钟数 - 在本例中为15作为额外参数来设置粒度。

public static Date dateFloor (Date d, int m) {
    Date d2 = (Date) d.clone();
    d2.setMinutes((d2.getMinutes()/m)*m);
    return d2;
}

public static Date dateCeil (Date d, int m) {
    Date d2 = (Date) d.clone();
    d2.setMinutes(((d2.getMinutes()+m)/m)*m);
    //alternatively: d2.setMinutes((d2.getMinutes()/m)*m+m);
    return d2;
}

DateFloor可以计算before日期,并类似DateCeil计算after日期。

使用这些方法,方法很简单:

Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
    String line = sc.nextLine();
    Date date = csvDateFormat.parse(line);
    Date before = dateFloor(date,15);
    Date after = dateCeil(date,15);
    System.out.print(before);
    System.out.print(" <= ");
    System.out.print(date);
    System.out.print(" < ");
    System.out.println(after);
 }

只有两行用于实现业务逻辑 ...

您可以在线找到Ideone demo here

我没有进行csv解析,所以你仍然必须在逗号上拆分并提取第一部分。但那不是至关重要的部分。

对于您的给定输入 - 没有短划线(-) - 它提供以下输出:

Tue May 19 16:15:00 GMT 2015 <= Tue May 19 16:15:00 GMT 2015 < Tue May 19 16:30:00 GMT 2015
Tue May 19 16:15:00 GMT 2015 <= Tue May 19 16:20:00 GMT 2015 < Tue May 19 16:30:00 GMT 2015
Tue May 19 16:30:00 GMT 2015 <= Tue May 19 16:35:00 GMT 2015 < Tue May 19 16:45:00 GMT 2015
Tue May 19 16:00:00 GMT 2015 <= Tue May 19 16:10:00 GMT 2015 < Tue May 19 16:15:00 GMT 2015
Tue May 19 16:45:00 GMT 2015 <= Tue May 19 16:55:00 GMT 2015 < Tue May 19 17:00:00 GMT 2015

其他错误

您所做的一个概念性错误是,当您将日期格式化为字符串,并尝试生成最后15分钟部分时,它会将00附加到其中,从而导致时间低于实际时间,因为您的方法不会先增加小时数。

其他建议

您将I / O与计算某些内容的方法混合在一起。 控制器模式表示您必须拆分这些问题。此外,您最好使用csv解析器。如果您在"foo,bar",baz文件中使用.csv之类的字符串,则会在foobar之间进行分配。这不符合标准。

答案 2 :(得分:0)

我收到的答案都很棒,但我要部署的服务器只有1.5版的java版本,所以我不会使用很多API库,因为有些不兼容。

基本上我找到了一个解决方案:

while ((perLine = br.readLine()) != null) {

    // Split row per column
    String[] perColumn = perLine.split(",", -1);

    // Convert unix date to yyyyMMddHHmm
    java.util.Date time = new java.util.Date(Long.parseLong(perColumn[0]) * 1000);

    String csvDateNoDay = fileDateFormat.format(time).substring(0,10);
    long csvDateYsDay = fileDateFormat.parse(fileDateFormat.format(time)).getTime();

    // Date of the file to be created/used
    String fileDate = "";
    String fileUnixDate = "";

    for (int j = 0 ; j < per15Min.size() ; j++) {
        String[] s = per15Min.get(j).split(",", -1);
        long isBeforeDate = fileDateFormat.parse(csvDateNoDay + s[0]).getTime();
        long isAfterDate = fileDateFormat.parse(csvDateNoDay + s[1]).getTime();

        /* Compare the Date for each record versus the list of array:
         * Record (Minutes) Array  Filename Date
         *     00 - 14       00    yyyyMMddHH00
         *     15 - 29       15    yyyyMMddHH15
         *     30 - 44       30    yyyyMMddHH30
         *     45 - 59       45    yyyyMMddHH45
         */     
        if ((csvDateYsDay>isBeforeDate && csvDateYsDay<isAfterDate) || csvDateYsDay==isBeforeDate) { 
            fileDate = csvDateNoDay + s[0];
            fileUnixDate = String.valueOf(isBeforeDate);
        }    
    }
}

fileDate和fileDateUnix字符串将具有正确的日期,该日期将用于命名新的csv文件并根据每15分钟的时间戳拆分每个recod。