0

我正在开发一个应用程序,我在每次使用之间存储一些信息,这些数据基本上可以归结为计算今天、本周、本月和应用程序生命周期中发生的事件的次数。我将此数据存储在 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;
    }   

我认为这应该没问题,但是我遇到的问题是测试,今天的测试很容易,但是测试月份逻辑需要等待一个月,或者编写一个使用日历 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;
    }   
4

3 回答 3

1

你应该只使用Joda-Time。如果您这样做,您的代码将变为:

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

等等......它不需要比 JDK 本身更多的依赖项,并且可以在 Android 上运行。希望有帮助。

于 2013-02-08T21:03:04.257 回答
1

除了使用名为“today”的变量并将其设置为所有非“Today”的事物的可读性挑战之外,您并没有处理时间。

如果现在是 3:20,并且在 1 月 31 日下午 5:00 发生了一些事情,我们可能仍希望将其视为 1 月发生的事情?您还应该将与时间相关的字段最大化到一天结束。

对于一周的事情,如果有人在星期天被认为是一周的第一天的地方执行,那可能会一团糟。您可能要考虑使用系统的一周的第一天,而不是星期日。

另外可能值得注意的是,这明确取决于使用Calendar.add()才能正常工作。 cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) -1);不是一回事,会被打破。

于 2013-02-07T22:22:02.753 回答
0

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

是的,您应该使用Joda-Time。比 Java 捆绑的臭名昭著的麻烦 java.util.Date 和 .Calendar 类更先进和有用。

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

您应该用简单的陈述句准确地定义“今天”、“本周”和“本月”的含义。例如,“今天”……

  • 你是说最后24小时吗?
  • 您的意思是从 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++;
    }
}

转储到控制台...</p>

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 );

运行时……</p>

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
于 2014-03-05T12:42:44.880 回答