我有一个订单对象
public class Order{
private Date orderDate;
//other fields + getters & setters
}以及订单列表(List< Orders>)。现在,我想根据类似的orderDate (这里类似的意思是,相同的年份、月份和日数)将此订单列表分组,并生成如下地图:
Map<Date, List<Order>> orderMap = new HashMap<>();如何在Java 8+中做到这一点?
请注意,我们可能有相似的日期,但时间戳不同,这意味着我们希望以“年、月、日”为基础。
发布于 2019-05-25 15:53:14
tl;dr
作为你的Map< LocalDate , List< Order> >的钥匙
order
.getDate() // Accessor method to retrieve your `java.util.Date` object.
.toInstant() // Convert from terrible legacy class `Date` to modern `java.time.Instant` class. Both represent a moment in UTC.
.atZone( // Adjust from UTC to the time zone used by your business.
ZoneId.of( "America/Los_Angeles" )
) // Remember: For any given moment, the date varies around globe by time zone, “tomorrow” in Tokyo while “yesterday” in Montréal.
.toLocalDate() // Extract the date-only portion, without time-of-day, without time zone, to use as the key in our map.保留您的Date成员
如果不能从可怕的orderDate类中更改java.util.Date成员变量的类型,那么在java.time中执行业务逻辑。使用添加到旧类的新方法转换为/从Date转换。
不要使用LocalDateTime
在其他答案中已经讨论过使用java.time,但是那些使用错误类的是:LocalDateTime。这完全是错误的类使用,因为它不代表一个时刻。它代表了全球时区范围约26-27小时的潜在时刻。这个类拥有一个日期和一天的时间,但没有时区的概念或与世界协调时相抵消的概念。因此,如果一个LocalDateTime物体在今年1月23日下午12点举行,我们不知道那是东京的中午,加尔各答的中午,巴黎的中午,或者蒙特雷的中午--所有的时刻,相隔几个小时都是非常不同的时刻。
要表示某一时刻,请使用以下内容之一:
Instant
在世界协调时的一个时刻OffsetDateTime
与世界协调时相抵消的时刻,一些小时-分钟-秒。ZonedDateTime
通过特定区域的人使用的偏移量所看到的时刻,该时区具有Continent/Region格式的名称。

Date➙Instant
java.util.Date的替代品是java.time.Instant。两者都代表了UTC中的一个时刻,尽管Instant对纳秒的分辨率比毫秒更高。
Instant instant = orderDate.toInstant() ;时区
调整从UTC到您想要的时区。你想知道在加州巴斯托看到的日期吗?使用America/Los_Angeles时区。应用ZoneId来获得ZonedDateTime。此ZonedDateTime表示与Instant相同的时间点、时间线上的相同点,但使用的是不同的挂钟时间。
以Continent/Region格式指定Continent/Region,如America/Montreal、Africa/Casablanca或Pacific/Auckland。不要使用2-4字母的缩写,如EST或IST,因为它们不是真正的时区,不标准化,甚至不是唯一的(!)。
请注意,java.time按设计使用不可变对象对螺纹安全进行了分类。因此,您可以定义这个ZoneId一次,并保持它的周围,以便重用,甚至跨线程。
ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, different wall-clock-time.LocalDate
提取日期的部分,没有时间的一天和没有时区.
LocalDate ld = zdt.toLocalDate() ; // The date as seen for this moment in Barstow, California.使用LocalDate作为Map< LocalDate , List< Order> >的密钥。
将Date成员更改为Instant
如何在Java 8+中做到这一点?
最好将代码从可怕的遗留日期-时间类迁移到现代的java.time类。Sun、Oracle和JCP社区在采用JSR 310时放弃了旧类。所以你应该.他们真的那么糟糕。
通常最好的后端工作,思考,存储和交换日期-时间值的UTC.仅将时区应用于(a)对用户的表示,(b)如果业务逻辑需要的话。
public class Order{
private Instant whenOrdered ;
//other fields + getters & setters
}应用上面看到的相同的时区调整逻辑,得到一个LocalDate作为Map< LocalDate , List< Order > >的关键。
在用户喜欢的时区中向用户显示Instant。让java.time 自动本地化显示文本。
Locale locale = new Locale( "fr" , "TN" ) ; // French in Tunisia.
ZoneId userZone = ZoneId.of( "Africa/Tunis" ) ; // Or ZoneId.systemDefault() to get the JVM’s current default time zone (appropriate to a client machine, but not a server machine).
String outputForDisplay =
order
.whenOrdered
.atZone( userZone ) // Adjust from UTC to time zone, going from `Instant` to `ZonedDateTime`.
.format( // Generate text representing the value inside our `ZonedDateTime` object.
DateTimeFormatter.ofLocalizedDateTime( FormatStyle.LONG ) // Let java.time automatically localize, rather than hard-code a formatting pattern.
)
;如果您只关心日期,而不关心一天的时间,并且不关心跨时区确定日期的模糊性(您在本地的一个小企业中),那么请使用LocalDate。
public class Order{
private LocalDate dateOrdered ;
//other fields + getters & setters
}关于java.time
http://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html框架内置到Java8和更高版本中。这些类取代了麻烦的旧遗赠日期时间类,如java.util.Date、Calendar和SimpleDateFormat。
要了解更多信息,请参见http://docs.oracle.com/javase/tutorial/datetime/TOC.html。并搜索堆栈溢出以获得许多示例和解释。规范是JSR 310。
http://www.joda.org/joda-time/项目现在在维护模式中,建议迁移到java.time类。
您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC 4.2。不需要字符串,也不需要java.sql.*类。
在哪里获得java.time类?
三次-额外项目使用其他类扩展java.time。这个项目是将来可能加入java.time的试验场。您可以在这里找到一些有用的类,如Interval、YearWeek、YearQuarter和更多。
发布于 2019-05-25 13:09:19
由于不推荐使用Date类并保存实际日期和时间,所以可以在Order类中使用LocalDateTime作为字段。然后,您可以根据从LocalDate获得的LocalDateTime对订单进行分组:
List<Order> list = new LinkedList<>();
Map<LocalDate, List<Order>> collect = list.stream()
.collect(Collectors.groupingBy(order -> order.getOrderDate().toLocalDate()));LocalDate在没有时间的情况下举行年度、月和日。
发布于 2019-05-25 13:07:32
您可以创建一个返回订单“相似性”的方法,例如:
public class Order{
private Date orderDate;
//other fields + getters & setters
public String getStringDate(){
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
return dateFormat.format(this.orderDate);
}
}然后在上面分组:
Map<String, List<Order>> ordersWithSimilarOrderDate = orders.stream().collect(Collectors.groupingBy(Order::getStringDate));https://stackoverflow.com/questions/56304807
复制相似问题