每15分钟的Java日期时间比较
我有一个csv记录,时间戳为或每5分钟一次:每15分钟的Java日期时间比较,java,date,datetime,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 ArrayList<String> per15Min = new ArrayList<String>() {{ add("00,15"); add("15,30"); add("30,
- 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
ArrayList<String> per15Min = new ArrayList<String>() {{
add("00,15");
add("15,30");
add("30,45");
add("45,00");
}};
我使用数组来比较每条记录的日期是否在15分钟内:
- 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
ArrayList<String> per15Min = new ArrayList<String>() {{
add("00,15");
add("15,30");
add("30,45");
add("45,00");
}};
我需要的是,如果时间戳(每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条件有什么问题吗?任何时候你需要处理日期/时间信息,你都应该使用合适的API,在你的情况下你可以避开日期和日历,但是如果可以的话最好使用Java 8的时间API或者Joda time,因为交互比日历更简单 将
字符串
日期值转换为日期
s或(更好的是)LocalDateTime
值,并使用它们的比较方法
之前,日期#在
之后,日期#在
日期#等于
之前,LocalDateTime#在
之后,LocalDateTime#在
LocalDateTime#等于
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
和15-30
…时间xx:15.00
到哪里去了?在这两个集合中?任何时候需要处理日期/时间信息时,您都应该使用适当的API,在您的情况下,您可以使用date
和Calendar
,但如果可以,最好使用Java8的时间API或Joda time,因为交互比Calendar
更简单
将字符串
日期值转换为日期
s或(更好的是)LocalDateTime
值,并使用它们的比较方法
之前,日期#在
之后,日期#在
日期#等于
之前,LocalDateTime#在
之后,LocalDateTime#在
LocalDateTime#等于
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
和15-30
…时间xx:15.00
到哪里去了?在这两组代码中?您提供的代码显示了许多不良气味(或反模式):计算机科学家通过经验发现的模式会导致许多问题
最大的问题是您依赖于字符串格式和解析
只对文本使用字符串,而不是作为元组、日期等各种数据的中间表示形式
特别是对于文化相关的概念,如Date的,这可能会导致完全混乱。例如,某些文化可能不使用阿拉伯数字(如12
)书写日期,但例如使用罗马数字(如XII
)。或者,在某个时间点,年份将不再可以用四位数字表示,或者一位使用时区12:15:57 UTC+01
解析日期,但在格式化和解析过程中,时区会丢失。一般来说,使用字符串处理进行数据处理是一个坏主意,只有当数据是text/names/strings/…时才这样做
接下来,您似乎存储了15
的倍数,这有点没用了。这将减缓这一进程
不要显式地存储倍数等,只使用蛮力方法(如果绝对必要,可以枚举元素)
在这个回答中,我提出了两种方法:dateFloor(dated,int m)
和datecel(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
可以计算日期之前的,并模拟dateceli
计算日期之后的
使用这些方法,方法非常简单:
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);
}
其他错误
您犯的一个概念性错误是,当您将日期格式化为字符串,并尝试生成最后的15
minutes部分时,它会将00
附加到该部分,导致时间低于实际时间,因为您的方法不会先增加小时数
附加建议
您可以将I/O与计算某些内容的方法混合使用。控制器模式要求您必须拆分这些关注点。此外,您最好使用csv解析器。如果您使用像“foo,bar”这样的字符串,baz
在.csv
文件中,您将在foo
和bar
之间进行分割。这不符合标准。您提供的代码显示了许多不良气味(或反模式):计算机科学家通过经验发现的模式会导致许多问题
最大的问题是您依赖于字符串格式和解析
只对文本使用字符串,而不是作为元组、日期等各种数据的中间表示形式
特别是对于依赖于文化的概念,如日期,这可能会导致完全混乱。例如,某些文化可能不使用阿拉伯数字(如12
),但例如使用罗马数字(如XII
)。或者,在某个时间点,年份将不再可以用四位数字表示,或者一位使用时区12:15:57 UTC+01
解析日期,但在格式化和解析过程中时区丢失。通常,使用字符串处理进行数据处理是一个坏主意,只有在数据为文本/名称时才这样做/字符串/
接下来,您似乎要存储多个15
,这有点没用。这会减慢进程
不要显式地存储倍数等,只使用蛮力方法(如果绝对必要,可以枚举元素)
在这个回答中,我提出了两种方法:dateFloor(dated,int m)
和dateceli(Date d,int m)
。您可以将分钟数作为一个额外的pa传递
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
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);
}
}
}