按日期分组对象:我是白痴吗?

时间:2009-11-01 14:44:44

标签: java

我有一个名为Activity的对象列表:

class Activity {
   public Date activityDate;
   public double amount;
}

我想迭代List,按日期对它们进行分组并返回一个新列表。这就是我目前所做的事情:

private List<Activity> groupToList(List<Activity> activityList) {
    SimpleDateFormatter sdf = new SimpleDateFormatter("YYYY-MM-DD");
    Map<String,Activity> groupMap = new HashMap<String,Activity>();
    for (Activity a in activityList) {
        String key = sdf.format(a.getActivityDate());
        Activity group = groupMap.get(key);
        if (group == null) {
          group = new Activity();
          groupMap.add(key, group);
        }
        group.setAmount(group.getAmount() + a.getAmount());
    }
    return new ArrayList<Activity>(groupMap.values()); 
}

以这种方式使用DateFormatter是一个WTF吗?

  • 我正在使用DateFormatter,因为每个activityDate都有时间信息。

5 个答案:

答案 0 :(得分:2)

我只想使用日期对象本身作为关键字。如果由于日期对象是可变的而困扰你,那么使用它的toString()值。没理由去制作格式。

如果您希望通过删除时间组件来规范化日期,那么使用Activity对象并删除时间组件会更好。如果问题仍然存在潜在的时区问题,我会使用JodaTime,但是JDK中没有任何对象代表一个没有时间的纯日期,所以使用字符串并不是很离谱,但它应该是隐藏在Activity对象中的方法后面,以及它是一个没有时间组件的日期格式化字符串这一事实应该是一个实现细节。

答案 1 :(得分:1)

java.util.Date是一个非常糟糕的抽象,可满足您的需求;如果没有什么比这更好的话,IMO公平地坚持使用字符串,但是Joda-time为您提供了一个很好的数据类型:DateMidnight或者LocalDate如果Activity是严格的timezome-independant。

除此之外,代码对我来说很好,你可以使用Multimap的实现来缩短它,以避免凌乱的空检查代码。说实话,它不会比你的解决方案短得多:

    public List<Activity> groupedByDate(List<Activity> input) {
    //group by day
    final Multimap<DateMidnight, Activity> activityByDay 
   = Multimaps.index(input, new Function<Activity, DateMidnight>() {
            @Override
            public DateMidnight apply(Activity from) {
                return new DateMidnight(from.activityDate);
            }
        });
    //for each day, sum up amount
    List<Activity> ret = Lists.newArrayList();
    for (DateMidnight day : activityByDay.keySet()) {
        Activity ins = new Activity();
        ins.activityDate = day.toDate();
        for (Activity activity : activityByDay.get(day)) {
            ins.amount+=activity.amount;
        }
    }
    return ret;
}

答案 2 :(得分:0)

为什么不简单地使用HashMap<Date, Activity>()创建String而不是迂回方式?

抱歉,我没有回答这个问题。答案是:是的,除非是白痴;)

答案 3 :(得分:0)

如果您使用了TreeMap并且提供了仅比较年,月和日而非时间的比较器,则可以使用日期作为键来执行此操作。

答案 4 :(得分:0)

如前所述,最佳解决方案是用 day precission 表示您的日期。如果这不可能 joda 是很好的库。

如果您可以忽略夏令时,则可以更轻松地按日期分组。 unix time 天是86 400 s长。时间戳确实忽略闰秒。 (您的计时器停止一秒钟或闰秒以某种方式分配。)所有日期值 day 等于同一天:

int msPerDay = 86400 * 1000;
long day = new Date().getTime() / msPerDay

一个小问题是调整时区。对于我的时区CET(UTC / GMT +1小时),格林尼治标准时间将在我们之后开始:

new GregorianCalendar(2009, 10, 1, 1, 0).getTime().getTime() / msPerDay) ==
new GregorianCalendar(2009, 10, 2, 0, 59).getTime().getTime() / msPerDay) ==
new Date().getTime() / msPerDay

如果夏令时很重要,最好的方法是使用joda。规则只是针对实现的复杂和区域设置。