按时间戳每天聚合对象一周的时间跨度

时间:2014-07-18 15:34:17

标签: java android sql loops jodatime

我在基于每天的时间戳汇总数据一周的时间内遇到问题。有一个SQLite数据库,它有一个表,我保存步行数的步骤(timestamp列是UTC,created_At是当地时间,但我还是不使用created_at列)。

enter image description here

我想要做的是获取7天前发生的总数据,直到前一天的午夜。所以我有这个jodatime表达式来查找时间戳的开始和结束

long start = new DateTime().withMillisOfDay(0).minusDays(7).getMillis();
long end = new DateTime().withTimeAtStartOfDay().getMillis();
//start milli:1405029600000 DateTime: 2014-07-11 00:00:00
//end milli:1405634400000   DateTime: 2014-07-18 00:00:00

然后我执行这个sql命令:

SELECT * FROM pa_data WHERE timestamp BETWEEN 1405029600000 AND 1405634400000

而且我很确定它会返回正确的行(我已经在我的电脑上将android数据库结果与SQLite数据库浏览器进行了比较,两者都返回相同的行数)。为此,我尝试使用这个嵌套迭代:

我想要创建的对象是:

public class PhysicalActivityPerDay {

    private List<PhysicalActivity> mList;

    public PhysicalActivityPerDay(List<PhysicalActivity> list) {
        mList = new ArrayList<PhysicalActivity>(list);
    }

    //methods....

}

现在问题是,我希望有一个数据对象可以保存每天的行。

List<PhysicalActivity> all = getPhysicalActivitiesBetween(start, end);
List<PhysicalActivityPerDay> perDays = new ArrayList<PhysicalActivityPerDay>();
List<PhysicalActivity> tempList;
PhysicalActivityPerDay tempPerDay;    

for (int i = 0; i < 7; i++) {

    long begin = start;
    long stop = (begin + 86400000); //add 24 hours

    tempList = new ArrayList<PhysicalActivity>();

    for (int j = 0; j < all.size(); j++) {

        PhysicalActivity p = all.get(j);
        DateTime when = new DateTime(p.getTimestamp());

        if (when.isAfter(start) && when.isBefore(stop)) {
            tempList.add(p);
            all.remove(j); //remove the matching object from the list
        }
    }

    tempPerDay = new PhysicalActivityPerDay(tempList);
    perDays.add(tempPerDay);

    start += 86400000; //add 24 hours or 1 day for next iteration
}

return perDays;

但结果完全出乎意料。有许多行与上面的if语句不匹配。我做了一个调试,这就是发生的事情:

Log.w(TAG, "There are totally " + all.size() + " physical activities for day for 7 days");
//There are totally 6559 physical activities for day for 7 days

但是,当我检查all列表(DB返回的总行数)时,虽然我从中删除匹配的对象,但如果我在嵌套迭代后查询其大小,那么令人惊讶的是它仍包含许多对象,告诉我迭代没有成功!

//Remaining: 3278 records after iterations from 6559

我做错了什么?请帮我看看!

2 个答案:

答案 0 :(得分:1)

不确定这是否是唯一的问题:

您正在循环all列表,并删除项目。 当您致电all.remove(j)时,过去位于第j + 1位置的项目将移至poisition j。这意味着你的for循环会跳过该项。

解决此问题的一种方法是,只有在您不从列表中删除项目时才增加j。

for (int j = 0; j < all.size();) {

    PhysicalActivity p = all.get(j);
    DateTime when = new DateTime(p.getTimestamp());

    if (when.isAfter(start) && when.isBefore(stop)) {
        tempList.add(p);
        all.remove(j); //remove the matching object from the list
    } else {
        j++;
    }
}

实际上,我并不完全确定在此修复之后循环是否可行。这取决于在每次迭代中是否评估all.size()。如果它不是,即使您要删除项目,它也会期望列表具有初始元素数。在这种情况下,当您第一次尝试访问超出数组最后一个索引的索引时,您可能会遇到异常。

如果出现异常,可以用while循环替换循环:

Iterator<PhysicalActivity> iter = all.iterator();
while (iter.hasNext ()) {
  PhysicalActivity p = iter.next();
  ...
  if (...) {
    iter.remove();
  }
}

请参阅definition of List.remove()

  

public E remove(int index)

     

删除此列表中指定位置的元素。 向左移动任何后续元素(从索引中减去一个)

答案 1 :(得分:0)

如何让SQL为您执行聚合

    SELECT strftime('%W-%Y',dt) as weekYear, count(1) as occurencePerWeek 
    FROM SOMETABLE c GROUP BY weekYear;

http://sqlfiddle.com/#!5/e63c3/1