Java: как мне сгруппировать все даты java в соответствующую неделю?
Задача:
У меня есть большой список дат, и мне нужно организовать их все по неделям.
Вопрос:
Как мне сгруппировать даты по неделе года, в котором они находятся?
Пример Набора Данных
Date date = new SimpleDateFormat.parse("04/01/2015")
Date date = new SimpleDateFormat.parse("04/02/2015")
Date date = new SimpleDateFormat.parse("04/03/2015")
Date date = new SimpleDateFormat.parse("04/04/2015")
Date date = new SimpleDateFormat.parse("04/05/2015")
Date date = new SimpleDateFormat.parse("04/06/2015")
Date date = new SimpleDateFormat.parse("04/07/2015")
Date date = new SimpleDateFormat.parse("04/08/2015")
Date date = new SimpleDateFormat.parse("04/09/2015")
Желаемый Выход
HashMap<Date, Date> hashMap = groupByWeek(ArrayList<Date> dates);
printWeeklyGroupedDates();
Week 1:
04/01/2015
04/02/2015
04/03/2015
04/04/2015
04/05/2015
04/06/2015
04/07/2015
Week 2:
04/08/2015
04/09/2015
Что я пробовал
public Date getWhichYearlyWeek(Date date){
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.get(Calendear.WEEK_OF_YEAR);
//Need to return this as 'Date' but indicate which week this is for the TreeMap functionality below
return cal.getTime();
}
public TreeMap<Date, ArrayList<Date>> getWeeklyMappedDates(ArrayList<Date> dateArray){
TreeMap<Date, ArrayList<Date>> treeMap = new TreeMap<Date, ArrayList<Date>>
for(Date i : dateArray){
Date date = getWhichYearlyWeek(date);
if(!treeMap.containsKey(date))
treeMap.get(date).add(date);
else
treeMap.put(date, new ArrayList<Date>());
}
return treeMap;
}
7 ответов:
Вы можете просто отсортировать
ListизDates, используя пользовательскийComparator. Следующий пример сортирует даты по неделям года, а затем по датам, не знаю, хотите ли вы вторую часть, но это хорошая демонстрация...import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; public class Test { public static void main(String[] args) { try { SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); List<Date> dates = new ArrayList<Date>(25); dates.add(sdf.parse("04/01/2015")); dates.add(sdf.parse("04/02/2015")); dates.add(sdf.parse("04/03/2015")); dates.add(sdf.parse("04/04/2015")); dates.add(sdf.parse("04/05/2015")); dates.add(sdf.parse("04/06/2015")); dates.add(sdf.parse("04/07/2015")); dates.add(sdf.parse("04/08/2015")); dates.add(sdf.parse("04/09/2015")); int week = 0; int woy = -1; Collections.sort(dates, new WeekComparator()); for (Date date : dates) { if (woy != getWeekOfYear(date)) { woy = getWeekOfYear(date); week++; System.out.println("Week " + week + ":"); } System.out.println(date); } } catch (ParseException exp) { exp.printStackTrace(); } } public static class WeekComparator implements Comparator<Date> { @Override public int compare(Date o1, Date o2) { int result = getWeekOfYear(o1) - getWeekOfYear(o2); if (result == 0) { result = o1.compareTo(o2); } return result; } } protected static int getWeekOfYear(Date date) { Calendar cal = Calendar.getInstance(); cal.setTime(date); return cal.get(Calendar.WEEK_OF_YEAR); } }Который выводит
Week 1: Wed Apr 01 00:00:00 EST 2015 Thu Apr 02 00:00:00 EST 2015 Fri Apr 03 00:00:00 EST 2015 Sat Apr 04 00:00:00 EST 2015 Week 2: Sun Apr 05 00:00:00 EST 2015 Mon Apr 06 00:00:00 EST 2015 Tue Apr 07 00:00:00 EST 2015 Wed Apr 08 00:00:00 EST 2015 Thu Apr 09 00:00:00 EST 2015Java 8 Time API
И только потому, что мне нужна практика...
import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.temporal.WeekFields; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Locale; public class Test { public static void main(String[] args) { SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MM/dd/yyyy"); List<LocalDate> dates = new ArrayList<LocalDate>(25); dates.add(LocalDate.parse("04/01/2015", dtf)); dates.add(LocalDate.parse("04/02/2015", dtf)); dates.add(LocalDate.parse("04/03/2015", dtf)); dates.add(LocalDate.parse("04/04/2015", dtf)); dates.add(LocalDate.parse("04/05/2015", dtf)); dates.add(LocalDate.parse("04/06/2015", dtf)); dates.add(LocalDate.parse("04/07/2015", dtf)); dates.add(LocalDate.parse("04/08/2015", dtf)); dates.add(LocalDate.parse("04/09/2015", dtf)); int week = 0; int woy = -1; Collections.sort(dates, new WeekComparator()); for (LocalDate date : dates) { if (woy != getWeekOfYear(date)) { woy = getWeekOfYear(date); week++; System.out.println("Week " + week + ":"); } System.out.println(date); } } public static class WeekComparator implements Comparator<LocalDate> { @Override public int compare(LocalDate o1, LocalDate o2) { int result = getWeekOfYear(o1) - getWeekOfYear(o2); if (result == 0) { result = o1.compareTo(o2); } return result; } } protected static int getWeekOfYear(LocalDate date) { WeekFields wf = WeekFields.of(Locale.getDefault()); return date.get(wf.weekOfYear()); } }Который выводит
Week 1: 2015-04-01 2015-04-02 2015-04-03 2015-04-04 Week 2: 2015-04-05 2015-04-06 2015-04-07 2015-04-08 2015-04-09В любом случае вы можете сопоставить каждую из дат в
Map, настроенную по неделе, но это зависит от вас
Если бы Java 8 была доступна:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy"); TemporalField weekOfYear = WeekFields.of(Locale.getDefault()).weekOfYear(); Stream.of( "04/01/2015" , "04/02/2015" , "04/03/2015" , "04/04/2015" , "04/05/2015" , "04/06/2015" , "04/07/2015" , "04/08/2015" , "04/09/2015" ) .collect(Collectors.groupingBy( d -> LocalDate.parse(d, formatter).get(weekOfYear), LinkedHashMap::new, Collectors.toList() )) .forEach((week, dates) -> { System.out.println("Week " + week + ":"); dates.forEach(System.out::println); });Эта печать (с использованием локали
de_CHна моем компьютере)Week 14: 04/01/2015 04/02/2015 04/03/2015 04/04/2015 04/05/2015 Week 15: 04/06/2015 04/07/2015 04/08/2015 04/09/2015
Используйте код ниже, чтобы получить номер недели:
public static int getWeek(Date date) { Calendar cal = Calendar.getInstance(); cal.setTime(date); return cal.get(WEEK_OF_YEAR); }
Поскольку вы упомянули, что вам нужно вернуть дату, попробуйте использовать
Calendar#clear(), а затемCalendar#setTime(Date), а затем использовать Calendar#get(календарь.НЕДЕЛЬ-ЛЕТ).Поскольку
#getWhichYearlyWeek(Date)теперь является избыточным, вы можете пропустить его вообще.
For не может работать так, как вы его реализовали, вот некоторые исправления:
for (Date i : dateArray) { Date date = getWhichYearlyWeek(date); if(treeMap.containsKey(date)) treeMap.get(date).add(i); else { ArrayList<Date> al = new ArrayList<Date>(); al.add(i); treeMap.put(date, al); } }
- Если бы не было, но этого не должно быть
- Вы добавили неделю вместо даты
- Вы забыли добавить дату в пустой список ArrayList
Использовать
GregorianCalendar:public Date getWhichYearlyWeek(Date date) { GregorianCalendar cal = new GregorianCalendar(); cal.setTime(date); // (*) = remove if you are only dealing with real dates and not dateTime cal.set(Calendar.HOUR_OF_DAY, 0); // (*) cal.clear(Calendar.MINUTE); // (*) cal.clear(Calendar.SECOND); // (*) cal.clear(Calendar.MILLISECOND); // (*) cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek()); // or Calendar.MONDAY return cal.getTime(); }
Вы можете попробовать этот код для группировки дат по WEEK_OF_YEAR.
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; public class GroupByWeekSampleCode { /** * @param year * @param weekOfYear * @return a unique hashcode generated from year and week of year */ public static int getYearWeekOfYearHashCode(int year, int weekOfYear) { int result = (int) (((float) year + ((float) weekOfYear / 100)) * 100); return result; } /** * @param hashCode * @return the week of year from this hash code */ public static int getWeekOfYearFromHashCode(int hashCode) { int year = (int) hashCode / 100; int weekOfYear = (int) (hashCode % year); return weekOfYear; } /** * @param hashCode * @return year from this hash code */ public static int getYearFromHashCode(int hashCode) { int year = (int) hashCode / 100; return year; } public static void main(String[] args) { try { List<Date> datesToGroup = new ArrayList<Date>(); SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); datesToGroup.add(sdf.parse("04/01/2015")); datesToGroup.add(sdf.parse("04/02/2015")); datesToGroup.add(sdf.parse("04/03/2015")); datesToGroup.add(sdf.parse("04/04/2015")); datesToGroup.add(sdf.parse("04/05/2015")); datesToGroup.add(sdf.parse("04/06/2015")); datesToGroup.add(sdf.parse("04/07/2015")); datesToGroup.add(sdf.parse("04/08/2015")); datesToGroup.add(sdf.parse("04/09/2015")); datesToGroup.add(sdf.parse("12/27/2015")); datesToGroup.add(sdf.parse("12/28/2015")); datesToGroup.add(sdf.parse("12/29/2015")); datesToGroup.add(sdf.parse("12/30/2015")); datesToGroup.add(sdf.parse("12/31/2015")); datesToGroup.add(sdf.parse("01/01/2016")); datesToGroup.add(sdf.parse("01/02/2016")); datesToGroup.add(sdf.parse("01/03/2016")); datesToGroup.add(sdf.parse("01/04/2016")); final Map<Integer, List<Date>> groupedDatesByWeekOfYear = new HashMap<Integer, List<Date>>() { private static final long serialVersionUID = 1L; @Override public List<Date> get(Object key) { List<Date> list = super.get(key); if (list == null) { list = new ArrayList<Date>(); super.put((Integer) key, list); } return list; } }; for (Date date : datesToGroup) { Calendar cal = Calendar.getInstance(); cal.setTime(date); Calendar previousYearLastDate = Calendar.getInstance(); previousYearLastDate.set(Calendar.YEAR, cal.get(Calendar.YEAR) - 1); previousYearLastDate.set(Calendar.MONTH, 11); previousYearLastDate.set(Calendar.DAY_OF_MONTH, previousYearLastDate.getActualMaximum(Calendar.DAY_OF_MONTH)); // a hash code generated from year and week of year value int yearWeekOfYearHashCode = 0; // to check if some of the dates in this week of year comes // in previous year last month, if true then the previous year // should be taken to generate hash code if (cal.get(Calendar.MONTH) == 0 && cal.get(Calendar.WEEK_OF_YEAR) == previousYearLastDate.get(Calendar.WEEK_OF_YEAR)) { yearWeekOfYearHashCode = getYearWeekOfYearHashCode(previousYearLastDate.get(Calendar.YEAR), previousYearLastDate.get(Calendar.WEEK_OF_YEAR)); } else { yearWeekOfYearHashCode = getYearWeekOfYearHashCode(cal.get(Calendar.YEAR), cal.get(Calendar.WEEK_OF_YEAR)); } groupedDatesByWeekOfYear.get(yearWeekOfYearHashCode).add(date); } for (Integer yearWeekOfYearHashCode : groupedDatesByWeekOfYear.keySet()) { System.out.println("year=" + getYearFromHashCode(yearWeekOfYearHashCode) + ", weekOfYear=" + getWeekOfYearFromHashCode(yearWeekOfYearHashCode) + ", dates under this week "); List<Date> datesInThisWeek = groupedDatesByWeekOfYear.get(yearWeekOfYearHashCode); for (Date date : datesInThisWeek) { System.out.println(date); Calendar cal = Calendar.getInstance(); cal.setTime(date); } System.out.println(); } } catch (ParseException e) { e.printStackTrace(); } } }Это выведет
year=2015, weekOfYear=1, dates under this week Sun Dec 27 00:00:00 IST 2015 Mon Dec 28 00:00:00 IST 2015 Tue Dec 29 00:00:00 IST 2015 Wed Dec 30 00:00:00 IST 2015 Thu Dec 31 00:00:00 IST 2015 Fri Jan 01 00:00:00 IST 2016 Sat Jan 02 00:00:00 IST 2016 year=2015, weekOfYear=14, dates under this week Wed Apr 01 00:00:00 IST 2015 Thu Apr 02 00:00:00 IST 2015 Fri Apr 03 00:00:00 IST 2015 Sat Apr 04 00:00:00 IST 2015 year=2015, weekOfYear=15, dates under this week Sun Apr 05 00:00:00 IST 2015 Mon Apr 06 00:00:00 IST 2015 Tue Apr 07 00:00:00 IST 2015 Wed Apr 08 00:00:00 IST 2015 Thu Apr 09 00:00:00 IST 2015 year=2016, weekOfYear=2, dates under this week Sun Jan 03 00:00:00 IST 2016 Mon Jan 04 00:00:00 IST 2016
Используйте возможности функционального программирования с потоками Java 8 и используйте новый Java Time Api:
Предполагая, что ваши даты находятся в коллекции, например:
List<LocalDate> dates = getMyDates(); WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY,7); Map<Integer, List<LocalDate>> datesGroupedByWeekNumber = dates.stream() .collect(Collectors.groupingBy(date -> date.get(weekFields.weekOfYear())));Вы получите карту, где ключевое целое число-это номер недели в году, а значение для этого ключа-список дат, где эти даты принадлежат этому номеру недели.
Comments