У меня есть объект Order
public class Order{
private Date orderDate;
//other fields + getters & setters
}
И список заказов (Список<Заказы>). Теперь я хочу сгруппировать этот список заказов на основе аналогичной даты заказа (аналогичный здесь означает тот же год, месяц и день) и создать такую карту:
Map<Date, List<Order>> orderMap = new HashMap<>();
Как это сделать в Java 8+?
Take note we might have similar date but different timestamp which means we want to based it on "year, month, day"
Даты @QBrute с одинаковым годом, месяцем, днем
@michalk не работает, если у нас разные часы, минуты, секунды в течение дня
Да, верно. Кстати, вы вынуждены использовать устаревшие классы для java.util? Существует пакет java.time, в котором есть такие классы, как LocalDate и LocalDateTime, которые следует использовать.
@michalk Пожалуйста, опубликуйте свое решение, каким бы оно ни было
Я рекомендую вам не использовать Date. Этот класс плохо спроектирован и давно устарел. Вместо этого используйте LocalDate из java.time, современный API даты и времени Java.




Вы можете создать метод, который возвращает «подобие» заказов, например:
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));
Эти ужасные классы даты и времени были вытеснены много лет назад современными классами Java.время, определенными в JSR 310. Предлагать их использовать в 2019 году — плохой совет.
Поскольку класс Date устарел и содержит фактическую дату и время, вы можете использовать LocalDateTime в качестве своего поля в классе Order. Затем вы можете сгруппировать свои заказы по LocalDate, взятым из LocalDateTime:
List<Order> list = new LinkedList<>();
Map<LocalDate, List<Order>> collect = list.stream()
.collect(Collectors.groupingBy(order -> order.getOrderDate().toLocalDate()));
Местная Дата содержит год, месяц и день без учета времени.
спасибо за ваш ответ, но у этого есть две проблемы: 1) я не хочу использовать LocalDate для своего ключа 2) toLocalDate для java.sql.Date не java.util.Date
toLocalDate — это метод класса LocalDateTime здесь.
@Mehdi Если вам нужна более тонкая детализация, чем LocalDate для ваших ключей, рассмотрите Instant. В Java 8+ никогда не используйте Date.
Я не очень поддерживаю идею делать все с помощью потоков, но вы можете это сделать. с жестким способом преобразования.
List<Order> orders = ... your list ...
Map<Date, List<Order>> orderMap = orders.stream().collect(Collectors.groupingBy(order->{
//Converting from Date to Instant
Instant dateInstant = order.getOrderDate().toInstant();
//Converting Instant to LocalDateTime and setting it to the start of the day
LocalDateTime dateTime = dateInstant.atZone(ZoneId.systemDefault()).toLocalDate().atStartOfDay();
//Converting it back to an instant
Instant startOfDayInstant = dateTime.atZone(ZoneId.systemDefault()).toInstant();
//Returning the util date
return Date.from(startOfDayInstant);
}));
Это при условии, что вы используете дату нужно. В противном случае я поддерживаю ответ от michalk
ваш ответ заслужил быть выбранным, если бы он был опубликован быстрее
@Mehdi Вы можете переключить свое согласие на другой ответ.
@BasilBourque Я знаю, но это неэтично. Всегда есть следующий раз, чувак
@Mehdi Stack Overflow — это не игра времени. Его основатели хотели, чтобы он был больше похож на Википедию, хранилище знаний для будущих поколений, а не на чат или форум. Вы можете изменить свое согласие спустя годы, если появится ответ, который лучше соответствует вопросу.
Если вам нужно использовать Date, вы все равно можете преобразовать его в LocalDate, предоставив информацию о часовом поясе.
Map<LocalDate, List<Order>> collect =
list.stream().collect(Collectors.groupingBy(order ->
order.getOrderDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()));
Как ключ к вашему 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.время. Преобразуйте в/из Date, используя новые методы, добавленные в старые классы.
LocalDateTimeИспользование Java.время обсуждалось в других ответах, но в них используется неправильный класс: LocalDateTime. Это совершенно неправильный класс для использования, так как нет представляет момент. Он представляет моменты потенциал в диапазоне примерно 26-27 часов, диапазоне часовых поясов по всему миру. Класс содержит дату и время дня, но не имеет понятия часового пояса или смещения от UTC. Так что, если объект LocalDateTime держит 12 часов дня 23 января этого года, мы понятия не имеем, должен ли был быть полдень в Токио, полдень в Калькутте, полдень в Париже или полдень в Монреале — все очень разные моменты, несколько часов. отдельно.
Чтобы представить момент, используйте один из них:
InstantOffsetDateTimeZonedDateTimeContinent/RegionDate ➙ InstantЗамена java.util.Date на java.time.Instant. Оба представляют момент в формате UTC, хотя Instant имеет более точное разрешение наносекунды по сравнению с миллисекундами.
Instant instant = orderDate.toInstant() ;
Настройте от UTC до желаемого часового пояса. Вы хотите, чтобы дата воспринималась так, как она видна в Барстоу, Калифорния? Используйте часовой пояс America/Los_Angeles. Примените ZoneId, чтобы получить ZonedDateTime. Этот ZonedDateTime представляет тот же момент, ту же точку на временной шкале, что и Instant, но использует другое время настенных часов.
Укажите правильное название часового пояса в формате Continent/Region, например America/Montreal, Africa/Casablanca или Pacific/Auckland. Никогда не используйте сокращения из 2-4 букв, такие как EST или IST, поскольку они представляют собой истинные часовые пояса нет, не стандартизированы и даже не уникальны (!).
Обратите внимание, что Java.время классифицирует потокобезопасный по дизайну, используя неизменяемые объекты. Таким образом, вы можете определить это 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 на InstantHow to do this in Java 8+ ?
Лучше всего перенести свой код с ужасных устаревших классов даты и времени на современные классы Java.время. Sun, Oracle и сообщество JCP отказались от старых классов, когда они приняли JSR 310. Так и вы — они действительно настолько плохи.
Как правило, на бэкэнде лучше всего работать, думать, хранить и обмениваться значениями даты и времени в формате UTC. Применяйте часовой пояс только для (а) представления пользователю, (б) если этого требует бизнес-логика.
public class Order{
private Instant whenOrdered ;
//other fields + getters & setters
}
Примените ту же логику настройки часового пояса, что и выше, чтобы получить LocalDate в качестве ключа к вашему Map< LocalDate , List< Order > >.
Покажите Instant пользователю в любом часовом поясе, который он предпочитает. Пусть Java.времяавтоматически локализовать отображаемый текст.
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.время встроена в Java 8 и более поздние версии. Эти классы заменяют проблемные старые классы даты и времени наследие, такие как java.util.Date, Calendar и SimpleDateFormat.
Чтобы узнать больше, см. Учебник по оракулу. И поищите множество примеров и пояснений в Stack Overflow. Спецификация JSR 310.
Проект Джода-Время, теперь именуемый Режим технического обслуживания, рекомендует перейти на классы Java.время.
Вы можете обмениваться объектами Java.время напрямую с вашей базой данных. Используйте JDBC-драйвер, совместимый с JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в классах java.sql.*.
Где получить классы java.time?
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является испытательным полигоном для возможных дополнений к java.time в будущем. Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и более.
правильный и правильный ответ с невероятным профессионализмом. Я кое-что узнал в этом ответе. Но иногда быстрое и простое исправление «достаточно хорошо», поскольку этот код можно использовать в большом программном обеспечении, которое в конечном итоге основано на util.date, и изменение всего потребует слишком много времени и денег. Если у кого-то есть такая же проблема в небольшом проекте, идите по этому пути, а не простому и быстрому решению.
Дайте определение «похожему»