我有一个带有时间戳的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条件有什么问题吗?
答案 0 :(得分:2)
每当您需要处理日期/时间信息时,您应该使用适当的API,在您的情况下,您可以使用Date
和Calendar
,但最好使用Java如果可以,可以使用8&#39的时间API,或者Joda-Time,因为交互比Calendar
更简单
将String
日期值转换为Date
s或(更好)LocalDateTime
值并使用其比较方法
Date#before
,Date#after
,Date#equals
LocalDateTime#isBefore
,LocalDateTime#isAfter
,LocalDateTime#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-15
和15-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
之类的字符串,则会在foo
和bar
之间进行分配。这不符合标准。
答案 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。