将java日期分解为小时
我在程序中收到以下开始日期和结束日期作为输入 2017-03-07 06:30:00至2017-03-07 11:35:00(yyyy-mm-dd hh:mi:ss) 我想把日期按小时分类。对于我上面给出的示例,我想创建一个类似于下面列出的值的列表将java日期分解为小时,java,Java,我在程序中收到以下开始日期和结束日期作为输入 2017-03-07 06:30:00至2017-03-07 11:35:00(yyyy-mm-dd hh:mi:ss) 我想把日期按小时分类。对于我上面给出的示例,我想创建一个类似于下面列出的值的列表 2017-03-07 0630-07 2017-03-07 07-08 2017-03-07 08-09 2017-03-07 09-10 2017-03-07 10-11 2017-03-07 11-1135 您能推荐一种我可以探
2017-03-07 0630-07
2017-03-07 07-08
2017-03-07 08-09
2017-03-07 09-10
2017-03-07 10-11
2017-03-07 11-1135
您能推荐一种我可以探索的方法吗?如果您可以使用Java8,我建议您使用以下方法:
// with LocalDateTime startDate and LocalDateTime endDate defined,
LocalDateTime currentRangeStart = startDate;
while (currentRangeStart.isBefore(endDate)) {
LocalDateTime nextHour = currentRangeStart.withMinute(0).plusHours(1);
LocalDateTime currentRangeEnd = nextHour.isBefore(endDate) ? nextHour : endDate;
System.out.printf("%s - %s%n", currentRangeStart, currentRangeEnd);
currentRangeStart = currentRangeEnd;
}
你可以在行动中看到它。如果当前有
Date
对象,请检查如何从Date
转换为LocalDateTime
我将构建一个从开始日期到计数的映射。类似于
Map<java.util.Date,Integer> map = new TreeMap<>();
Calendar cal = new GregorianCalendar();
for (java.sql.Timestamp exactDate: dates) {
cal.setTime(exactDate);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
java.util.Date key = new java.util.Date(cal.getTime());
Integer count;
if ((count = map.get(key)) == null) {
map.put(key, Integer.valueOf(1);
} else {
map.put(key, Integer.valueOf(1 + count.intValue()));
}
}
是好的,但它忽略输入中可能存在的任何秒或秒的分数。此外,我还可以进一步扩展,并应用时区
截断
您可以截断LocalDateTime
对象,在增加小时数时消除任何整秒或分数秒
LocalDateTime ldtTruncated = ldt.truncatedTo( ChronoUnit.MINUTES ); // Lop off seconds and nanoseconds.
……或者
LocalDateTime ldtTruncated = ldt.truncatedTo( ChronoUnit.HOURS ); // Lop off minutes, seconds, and nanoseconds.
时区
一个关键问题是时区。这些值缺少或的任何指标。正如Aaron所正确显示的,我们应该首先将它们解析为LocalDateTime
LocalDateTime ldtStart = LocalDateTime.parse ( "2017-03-07 06:30:00".replace ( " " , "T" ) );
LocalDateTime ldtStop = LocalDateTime.parse ( "2017-03-07 11:35:00".replace ( " " , "T" ) );
但从问题的措辞来看,我认为我们希望在特定时刻开展工作。根据定义,LocalDateTime
不是一个特定的时刻,只是一个潜在时刻的模糊概念。必须添加时区(或偏移)的上下文以确定实际时刻。因此,如果您知道用于这些值的区域,请应用它
ZonedDateTime
类对输入值进行调整,这些输入值对于您的特定时区无效,因为存在异常,例如
确保输入有意义
// Validate the inputs.
if ( zdtStop.isBefore ( zdtStart ) ) {
// perhaps throw exception
System.out.println ( "ERROR - stop is befor start." );
return;
}
日期时间范围作为一对ZonedDateTime
对象
现在我们可以逐小时递增以生成所需的范围。我们可以使用Three Ten Extra项目(见下文)中的Interval
类,该类跟踪始终以UTC为单位的一对Instant
对象。但这对我们来说可能没什么用处,因为我们真的很想使用分区时间(或者我想是这样)。因此,让我们将每个日期时间范围作为一对ZonedDateTime
类进行跟踪。我们可以为这一对创建我们自己的类,但相反,我们重新定义了类的用途。该类将一对对象作为键和值进行跟踪
不要让配对类的名称迷惑您。该类的最初目的是与映射一起使用,但其本身不是映射。该类是指一个键和一个来自映射的值,但我们将使用它的“键”是我们的开始时刻,它的“值”是我们的停止时刻
我们在AbstractMap.SimpleImmutableEntry
类型的列表中收集每个计算的时间范围
int initialCapacity = ( ( int ) ChronoUnit.HOURS.between ( zdtStart , zdtStop ) ) + 2; // Plus two for good measure. (not sure if needed).
List<AbstractMap.SimpleImmutableEntry<ZonedDateTime , ZonedDateTime>> ranges = new ArrayList<> ( initialCapacity );
跑步的时候
ldtStart/ldtStop:2017-03-07T06:30/2017-03-07T11:35
zdtStart/zdtStop:2017-03-07T06:30-05:00[美国/蒙特利尔]/2017-03-07T06:30-05:00[美国/蒙特利尔]
范围:[2017-03-07T06:30-05:00[美国/蒙特利尔]=2017-03-07T07:00-05:00[美国/蒙特利尔]、2017-03-07T07:00-05:00[美国/蒙特利尔]=2017-03-07T08:00-05:00[美国/蒙特利尔]=2017-03-07T08:00-05:00[美国/蒙特利尔]、2017-03-07T09:00-05:00[美国/蒙特利尔]、2017-03-03-07T09:00-05:00[美国/蒙特利尔]=2017-03-07T10:00[美国/蒙特利尔],2017-03-07T10:00-05:00[美国/蒙特利尔]=2017-03-07T11:00-05:00[美国/蒙特利尔]=2017-03-07T11:00-05:00[美国/蒙特利尔]=2017-03-07T11:35-05:00[美国/蒙特利尔]]
关于java.time
该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&
该项目现已启动,建议迁移到类
要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是
从哪里获得java.time类
- 后来
- 内置的李>
- 标准JavaAPI的一部分,带有捆绑实现
- Java9添加了一些次要功能和修复
- 及
- 大部分java.time功能都在中向后移植到Java6和Java7
-
- 该项目专门为Android采用了ThreeTen Backport(如上所述)
- 看
该项目使用其他类扩展了java.time。这个项目是java.time将来可能添加的一个试验场。你可以在这里找到一些有用的课程,如、、和。对不起,Aaron,我将退出我的帖子,并将清楚地解释它。好的,我现在明白了!我会看看能找到什么。谢谢亚伦,是的,没错。我想按时间跨度对它们进行细分。我还没有把这个编码。我想在实现之前检查一下推荐的方法。你完全可以用Java来做,但通常,当我做这类事情时,这是一次性的工作,我使用类似Python的东西。@PunterVicky标题中提到的地图是从哪里来的?我建议你要么更清楚地解释一下,要么编辑你的标题,删除与你的核心问题不相关的内容。太棒了,亚伦!非常感谢你的帮助。这看起来非常简单和优雅。是的,java 8中引入的java.time
包确实简化了日期处理:)再次感谢!感谢您的时间和帮助。正是我想要的。谢谢@David!!是的,我也按照你的建议从DB取回。
// Validate the inputs.
if ( zdtStop.isBefore ( zdtStart ) ) {
// perhaps throw exception
System.out.println ( "ERROR - stop is befor start." );
return;
}
int initialCapacity = ( ( int ) ChronoUnit.HOURS.between ( zdtStart , zdtStop ) ) + 2; // Plus two for good measure. (not sure if needed).
List<AbstractMap.SimpleImmutableEntry<ZonedDateTime , ZonedDateTime>> ranges = new ArrayList<> ( initialCapacity );
ZonedDateTime zdt = zdtStart;
while ( zdt.isBefore ( zdtStop ) ) {
ZonedDateTime zdt2 = zdt.truncatedTo ( ChronoUnit.HOURS ).plusHours ( 1 ); // Truncate to whole hour, and add one.
if ( zdt2.isAfter ( zdtStop ) ) { // Oops, went too far. Clip this range to end at `zdtStop`.
zdt2 = zdtStop;
}
AbstractMap.SimpleImmutableEntry<ZonedDateTime , ZonedDateTime> range = new AbstractMap.SimpleImmutableEntry<> ( zdt , zdt2 );
ranges.add ( range );
// Prepare for next loop.
zdt = zdt2;
}
System.out.println ( "ldtStart/ldtStop: " + ldtStart + "/" + ldtStop );
System.out.println ( "zdtStart/zdtStop: " + zdtStart + "/" + zdtStart );
System.out.println ( "ranges: " + ranges );