【问题标题】:Android java.util.Calendar - Time DifferenceAndroid java.util.Calendar - 时差
【发布时间】:2010-11-14 22:42:35
【问题描述】:

我想制作日历视图以支持触摸交互。 所以我想建立新的自定义日历视图。 我试图在视图偏移和实际日期值之间建立映射函数。

这是我的想法: 如果我可以计算自基准日期以来的周数(在我的情况下,1989-12-31), 很容易知道偏移量。 HEIGHT_FOR_WEEK * NUM_OF_WEEK 是非常简单的计算 知道确切的偏移量。

我的问题是: 首先,我从基准日期得到毫秒值。我将毫秒设置为 另一个日历对象。我希望该对象的日期相同。但实际上 这是不同的日期。

mBaseDateInMillis = mBaseDate.getTimeInMillis();
mAnotherDate.setTimeInMillis(mBaseDateInMillis);
/* I expect mBaseDate == mAnotherDate.
 * but it was different.
 */ 

这是我的代码:

public class CalendarCoordinate {
    public static final long ONEWEEK_IN_MILLISECONDS = 60 * 60 * 24 * 7 * 1000;
    public Calendar mBaseDate = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
    public long mBaseDateInMillis = 0;
    public Calendar mDate = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
    public int  mWeekHeight = 30;

    /**
     * CTOR
     */
    public CalendarCoordinate() {
        /* Base date is 1989-12-31 0, 0, 0
         * It was Sunday and offset 0 will be mapped onto this day.
         */
        mBaseDate.set(Calendar.MILLISECOND, 0);
        mBaseDate.set(1989, 12, 31, 0, 0, 0);
        mBaseDateInMillis = mBaseDate.getTimeInMillis();
        Log.v(TAG, "BaseDate:" + mBaseDate.toString());
    }

    /**
     * Compute DATE from Y-Offset
     * @param yOffset
     * @return
     */
     public Calendar dateFromYOffset(int yOffset) {
        long nthWeeks = yOffset / mWeekHeight;
        long millsSinceBaseDate = nthWeeks * ONEWEEK_IN_MILLISECONDS;
        mDate.clear();
        mDate.set(Calendar.MILLISECOND, 0);
        mDate.setTimeInMillis(mBaseDateInMillis + millsSinceBaseDate);

        /* We SHOULD call to update mDate internal data structure. 
         * Java is really strange for this thing
         **/
        mDate.getTimeInMillis();
        return mDate;
    }

    /**
     * Compute Y-Offset from DATE
     * @param date
     * @return
     */
    public long yOffsetFromDate(Calendar cal) {
        long mills = cal.getTimeInMillis();
        long nthWeeks = (mills - mBaseDateInMillis)/ONEWEEK_IN_MILLISECONDS;
        return nthWeeks * mWeekHeight;
    }
}

有人可以帮助我吗?我不是一个好的 Java 程序员。

【问题讨论】:

    标签: java android datetime


    【解决方案1】:

    这句话让我很困惑:

    /* I expect mBaseDate == mAnotherDate.
     * but it was different.
     */
    

    您是否真的试图通过比较来检查是否相等: if (mBaseDate == mAnotherDate) { System.out.println("它们是一样的"); }

    如果是这样,您的问题是您误解了“==”运算符在 Java 中的工作方式。它比较引用,而不是比较底层对象数据,因为这些是不同的对象(具有相同的值),所以总是错误的。有关更多详细信息,请参阅Java Notes on comparison operators。

    另外,这些台词在我看来真的很可疑:

    /* We SHOULD call to update mDate internal data structure. 
    * Java is really strange for this thing
    **/
    mDate.getTimeInMillis();
    

    如果 Android 有一个 bug 需要您执行此操作,我会感到非常惊讶,但我想一切皆有可能。如果没有这个电话,你会遇到什么样的问题?

    【讨论】:

      【解决方案2】:

      这是因为您需要使用“equals”方法来比较不同的对象。使用运算符“==”将告诉您对象是否相同(它们是否位于完全相同的内存位置),而“等于”比较函数将告诉您两个对象在逻辑上是否等效。

      【讨论】:

        【解决方案3】:

        tl;博士

        long weeks = ChronoUnit.WEEKS.between ( LocalDate.of ( 1989 , 12 , 31 ) , LocalDate.of ( 1990 , 1 , 14 ) ); // Results: 2
        

        避免从纪元开始计数

        不要以毫秒为单位工作。混淆、掩盖错误并忽略时区等问题。

        让一个好的日期时间库在这些计算中完成繁重的工作。

        java.time

        您正在使用麻烦的旧日期时间类,例如 java.util.Calendar。这些设计不佳的类已被 Java 8 及更高版本中内置的java.time 框架所取代。见Oracle Tutorial。大部分 java.time 功能已在 ThreeTen-Backport 中向后移植到 Java 6 和 7,并在 ThreeTenABP 中进一步适应 Android。

        ChronoUnit

        ChronoUnit 类计算经过的时间,例如一对 LocalDate(仅限日期,无时间或时区)值之间的整周数。

            LocalDate start = LocalDate.of ( 2016 , 1 , 1 );
            LocalDate stop = start.plusDays ( 17 ); // Ex: 13 days = 1 week. 14 days = 2 weeks.
        
            long weeks = ChronoUnit.WEEKS.between ( start , stop );
        

        转储到控制台。

            System.out.println ( "start: " + start + " | stop: " + stop + " | weeks: " + weeks );
        

        开始:2016-01-01 |停止:2016-01-18 |周:2

        如果您想要自 1989-12-31 之后的数周,请将其用作上面看到的 start 对象。

        LocalDate start = LocalDate.of( 1989 , 12 , 31 );
        

        半开

        但我注意到您的基准日期是一年中的最后一天。提示:时间跨度通常最好使用半开放方法处理,其中开始是包含,而结束是独占。所以你可能想使用1990-01-01作为你的基准日期(我不知道你的业务逻辑,所以只是我的猜测)。

        所以你的前两周将是这个(第 1 至 15 日):

        long firstTwoWeeks = ChronoUnit.WEEKS.between ( LocalDate.of ( 1990 , 1 , 1 ) , LocalDate.of ( 1990 , 1 , 15 ) );
        

        ...而不是这个(31 日 - 14 日):

        long firstTwoWeeks = ChronoUnit.WEEKS.between ( LocalDate.of ( 1989 , 12 , 31 ) , LocalDate.of ( 1990 , 1 , 14 ) );
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-11-23
          • 2012-07-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多