Android / Java - 测试日期是否为上个月

时间:2013-02-07 22:07:23

标签: java android date calendar

我正在开发一个应用程序,我在每次使用之间存储一些信息,这些数据基本上归结为计算今天,本周,本月和应用程序生命周期中事件发生的次数。我将这些数据存储在4个不同的计数器中,我可以使用SharedPreferences加载/保存。

除了数据我将应用程序的“最后运行时间”存储为日期,我的计划是在加载时我将加载计数器然后根据今天的日期测试存储的日期以确定需要清除哪些计数器

听起来很简单!

将我的头发拉出一段时间并在日历文档中前后移动后,我想我理解它们足以提出以下内容:

    Calendar last = Calendar.getInstance();
    last.setTimeInMillis(lastDate);

    Calendar today = Calendar.getInstance();
    today.add(Calendar.DATE, -1);

    if ( !last.after(today) )
    {
                     today = 0;
    }

    today.add(Calendar.WEEK_OF_MONTH, -1);
    today.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);

    if ( !last.after(today) )
    {
                     today = 0;
                     week = 0;
    }

    today = Calendar.getInstance();
    today.add(Calendar.MONTH, -1);
    today.set(Calendar.DATE, today.getActualMaximum(Calendar.DATE));

    if ( !last.after(today) )
    {
                     today = 0;
                     week = 0;
                     month = 0;
    }   

我认为这应该没问题,但是我的问题是测试,今天的测试很容易,但是测试月份逻辑需要等待一个月,或者编写一个使用Calendar API来模拟旧日期的测试用例但是,如果我对API工作方式的假设首先是错误的话,我就不能编写测试用例了!

因此,经过一大堆文本我的问题是......上面的代码块看起来是否合理,或者我完全误解了使用Java中的日期?

谢谢!

编辑:

第二遍代码:

这看起来更合理吗?如果我正确地理解了事情,我现在正试图将上次保存日期的结束与今天,本周和本月的开始进行比较。

Calendar last = Calendar.getInstance();
    last.setTimeInMillis(lastDate);

    last.set(Calendar.HOUR_OF_DAY, last.getActualMaximum(Calendar.HOUR_OF_DAY));
    last.set(Calendar.MINUTE, last.getActualMaximum(Calendar.MINUTE));
    last.set(Calendar.SECOND, last.getActualMaximum(Calendar.SECOND));
    last.set(Calendar.MILLISECOND, last.getActualMaximum(Calendar.MILLISECOND));

    Calendar todayStart = Calendar.getInstance();
    todayStart.set(Calendar.HOUR_OF_DAY, todayStart.getActualMinimum(Calendar.HOUR_OF_DAY));
    todayStart.set(Calendar.MINUTE, todayStart.getActualMinimum(Calendar.MINUTE));
    todayStart.set(Calendar.SECOND, todayStart.getActualMinimum(Calendar.SECOND));
    todayStart.set(Calendar.MILLISECOND, todayStart.getActualMinimum(Calendar.MILLISECOND));

    // If the last recorded date was before the absolute minimum of today
    if ( last.before(todayStart) )
    {
        todayCount = 0;
    }

    Calendar thisWeekStart = Calendar.getInstance();
    thisWeekStart.set(Calendar.HOUR_OF_DAY, thisWeekStart.getActualMinimum(Calendar.HOUR_OF_DAY));
    thisWeekStart.set(Calendar.MINUTE, thisWeekStart.getActualMinimum(Calendar.MINUTE));
    thisWeekStart.set(Calendar.SECOND, thisWeekStart.getActualMinimum(Calendar.SECOND));
    thisWeekStart.set(Calendar.DAY_OF_WEEK, thisWeekStart.getFirstDayOfWeek());
    thisWeekStart.set(Calendar.MILLISECOND, thisWeekStart.getActualMinimum(Calendar.MILLISECOND));

    // If the last date was before the absolute minimum of this week then clear
    // this week (and today, just to be on the safe side)
    if ( last.before(thisWeekStart) )
    {
        todayCount = 0;
        weekCount = 0;
    }

    Calendar thisMonthStart = Calendar.getInstance();
    thisMonthStart.set(Calendar.HOUR_OF_DAY, thisMonthStart.getActualMinimum(Calendar.HOUR_OF_DAY));
    thisMonthStart.set(Calendar.MINUTE, thisMonthStart.getActualMinimum(Calendar.MINUTE));
    thisMonthStart.set(Calendar.SECOND, thisMonthStart.getActualMinimum(Calendar.SECOND));
    thisMonthStart.set(Calendar.DAY_OF_MONTH, thisMonthStart.getActualMinimum(Calendar.MONTH));
    thisMonthStart.set(Calendar.MILLISECOND, thisMonthStart.getActualMinimum(Calendar.MILLISECOND));

    // If the last date was before the absolute minimum of this month then clear month...
    if ( !last.after(thisMonthStart) )
    {
        todayCount = 0;
        weekCount = 0;
        monthCount = 0;
    }   

3 个答案:

答案 0 :(得分:1)

除了使用名为“今天”的变量并将其设置为不是“今天”的所有方式的可读性挑战外,您还没有处理时间。

如果它现在是3点20分,而且事情发生在1月31日下午5点,我们可能仍然想要计算在1月份发生的情况?您应该将与时间相关的字段最大化到当天结束。

对于本周的事情,如果有人在星期日被认为是一周的第一天的地方执行,那么这可能是一个真正的混乱。您可能需要考虑使用系统的一周中的第一天,而不是周日。

同样值得注意的是,这明确取决于使用Calendar.add()来正常工作。 cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) -1); 同样的事情会被打破。

答案 1 :(得分:1)

您应该使用Joda-Time。如果你做了你的代码变成:

DateTime oneMonthAgo = new DateTime().minusMonths(1);
DateTime oneWeekAgo = new DateTime().minusWeeks(1);

依此类推......它不需要比JDK本身更多的依赖性,而且适用于Android。希望有所帮助。

答案 2 :(得分:0)

是的,您可以在Android上使用Joda-Time。 (据我所读;我不使用Android)

是的,您应该使用Joda-Time。与Java捆绑在一起的臭名昭着的java.util.Date和.Calendar类更加先进和有用。

你的问题和其他答案都忽略了时区的关键问题。时区定义了“今天”的含义以及其他日子的开始/结束。

你应该用简单的陈述句来定义你对“今天”,“本周”和“本月”的意思。例如,“今天”......

  • 你的意思是过去24小时?
  • 您的意思是从UTC时间00:00:00到明天但不包括00:00:00,在UTC / GMT时区(即没有时区偏移)?
  • 是指从今天的​​第一时刻开始,在给定的时区内(某些偏离UTC)直到但不包括明天的第一个时刻在同一时区?由于夏令时(DST)或其他异常,这可能不是24小时。

我太累了,无法解析你的代码。我不应该这样做。在编写此类日期时间代码之前,您应该用简单的英语拼出您的目标。日期时间工作非常棘手,所以你必须清楚自己的目标。

这是Joda-Time 2.3中的一些示例代码。

Joda-Time对大多数默认值使用ISO 8601标准。这包括一周的定义。星期一是第一天,编号为1,星期日是最后一天,编号为7。

当关注具有日期时间对象的“日”时,您可能希望从当天的第一时刻开始。如果是这样,请调用withTimeAtStartOfDay方法。要结束一天,不要。使用半开放式方法,您可以比较下一个日的第一个时刻,但不包括该时间。在StackOverflow的其他答案中可以找到解释。

Joda-Time提供3个类来处理时间跨度:Period,Duration和Interval。全部检查出来。在进行比较时,Joda-Time使用“半开”方法,其中开头是包含性的,结尾是独占的。当你思考它时,这是有道理的。搜索StackOverflow以获得更多讨论。

这里有一些示例代码可以帮到您。我采用一组任意的日期时间值。然后我将一些时间跨度定义为一天,一周前和一个月前。然后我会计算出有多少值属于这些范围。

String input = "2014-01-02T03:04:05Z";

DateTimeZone timeZone = DateTimeZone.forID( "America/Montreal" );

java.util.List<DateTime> dateTimes = new java.util.ArrayList<DateTime>();
DateTime dateTime1 = new DateTime( input, timeZone ); // Parse the string as being in Zulu time zone (UTC). Then adjust to Montréal time.
dateTimes.add( dateTime1 );
dateTimes.add( dateTime1.plusDays( 3 ) );
dateTimes.add( dateTime1.plusWeeks( 1 ) );
dateTimes.add( dateTime1.plusMonths( 1 ) );
DateTime now = new DateTime( timeZone );
dateTimes.add( now );
dateTimes.add( now.minusDays( 1 ) );
dateTimes.add( now.minusDays( 10 ) );

// Spans of time
Interval today = new Interval( now.withTimeAtStartOfDay(), now.plusDays( 1 ).withTimeAtStartOfDay() );
Interval pastWeek = new Interval( now.minusWeeks( 1 ).withTimeAtStartOfDay(), now.plusDays( 1 ).withTimeAtStartOfDay() );
Interval pastMonth = new Interval( now.minusMonths( 1 ).withTimeAtStartOfDay(), now.plusDays( 1 ).withTimeAtStartOfDay() );

int countTotal = dateTimes.size();
int countDay = 0;
int countWeek = 0;
int countMonth = 0;
for ( DateTime dateTime : dateTimes ) {
    if ( today.contains( dateTime ) ) {
        countDay++;
    }
    if ( pastWeek.contains( dateTime ) ) {
        countWeek++;
    }
    if ( pastMonth.contains( dateTime ) ) {
        countMonth++;
    }
}

转储到控制台...

System.out.println( "dateTimes: " + dateTimes );
System.out.println( "today: " + today );
System.out.println( "pastWeek: " + pastWeek );
System.out.println( "pastMonth: " + pastMonth );
System.out.println( "countTotal: " + countTotal );
System.out.println( "countDay: " + countDay );
System.out.println( "countWeek: " + countWeek );
System.out.println( "countMonth: " + countMonth );

跑步时......

dateTimes: [2014-01-01T22:04:05.000-05:00, 2014-01-04T22:04:05.000-05:00, 2014-01-08T22:04:05.000-05:00, 2014-02-01T22:04:05.000-05:00, 2014-03-05T07:40:25.508-05:00, 2014-03-04T07:40:25.508-05:00, 2014-02-23T07:40:25.508-05:00]
today: 2014-03-05T00:00:00.000-05:00/2014-03-06T00:00:00.000-05:00
pastWeek: 2014-02-26T00:00:00.000-05:00/2014-03-06T00:00:00.000-05:00
pastMonth: 2014-02-05T00:00:00.000-05:00/2014-03-06T00:00:00.000-05:00
countTotal: 7
countDay: 1
countWeek: 2
countMonth: 3