Android java.util.Calendar - 时差
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1198068/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android java.util.Calendar - Time Difference
提问by popopome
I want to make calendar view in order to support touch interaction. So I'd like to build new custom calendar view. I tried to make mapping function between view offset and real date value.
我想制作日历视图以支持触摸交互。所以我想构建新的自定义日历视图。我试图在视图偏移量和实际日期值之间创建映射函数。
Here is my idea: If I can compute the number of weeks since base date(in my case, 1989-12-31), it is easy to know offset. HEIGHT_FOR_WEEK * NUM_OF_WEEK is very simple computation to know exact offset.
这是我的想法:如果我可以计算自基准日期(在我的情况下,1989-12-31)以来的周数,很容易知道偏移量。HEIGHT_FOR_WEEK * NUM_OF_WEEK 是非常简单的计算来知道确切的偏移量。
My problem is this: First I got milliseconds value from base date. And I set the milliseconds to another calendar object. I expected same date from that object. But actually it was different date.
我的问题是:首先我从基准日期获得毫秒值。我将毫秒设置为另一个日历对象。我预计该对象的日期相同。但实际上是不同的日期。
mBaseDateInMillis = mBaseDate.getTimeInMillis();
mAnotherDate.setTimeInMillis(mBaseDateInMillis);
/* I expect mBaseDate == mAnotherDate.
* but it was different.
*/
Here is my code:
这是我的代码:
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;
}
}
Anybody can help me? I'm not a good Java programmer.
任何人都可以帮助我吗?我不是一个好的 Java 程序员。
回答by jsight
This statement confuses me:
这个说法让我很困惑:
/* I expect mBaseDate == mAnotherDate.
* but it was different.
*/
Are you actually trying to check for equality by doing the comparison: if (mBaseDate == mAnotherDate) { System.out.println("They are the same"); }
您是否真的试图通过比较来检查相等性: if (mBaseDate == mAnotherDate) { System.out.println("they are the same"); }
If so, your issue is that you are misunderstanding how the "==" operator works in Java. It compares references, rather than comparing the underlying object data, and since these are different objects (with the same values) that will always be false. For a lot more details, see the Java Notes on comparison operators.
如果是这样,您的问题是您误解了“==”运算符在 Java 中的工作方式。它比较引用,而不是比较底层对象数据,并且由于这些是不同的对象(具有相同的值),因此总是为假。有关更多详细信息,请参阅关于比较运算符的Java 注释。
Also, these lines look really suspicious to me:
此外,这些行在我看来真的很可疑:
/* We SHOULD call to update mDate internal data structure.
* Java is really strange for this thing
**/
mDate.getTimeInMillis();
I would really be surprised if Android had a bug requiring you to do this, but I guess anything is possible. What kind of problems do you have without this call?
如果 Android 有一个错误要求您这样做,我真的会感到惊讶,但我想一切皆有可能。没有这个电话你会遇到什么样的问题?
回答by Michael Aaron Safyan
This is because you need to use the "equals" method to compare different objects. Using operator "==" will tell you if the objects are identical (do they reside in the exact same memory location), while the "equals" comparison function will tell you if the two objects are logically equivalent.
这是因为您需要使用“equals”方法来比较不同的对象。使用运算符“==”将告诉您对象是否相同(它们是否驻留在完全相同的内存位置),而“等于”比较函数将告诉您两个对象在逻辑上是否相同。
回答by Basil Bourque
tl;dr
tl;博士
long weeks = ChronoUnit.WEEKS.between ( LocalDate.of ( 1989 , 12 , 31 ) , LocalDate.of ( 1990 , 1 , 14 ) ); // Results: 2
Avoid count-from-epoch
避免从纪元开始计数
Do not work in a count-since-epoch such as milliseconds. Confusing, cloaks bugs, and ignores issues such as time zones.
不要在自纪元(例如毫秒)中计数。混淆、隐藏错误并忽略时区等问题。
Let a good date-time library do the heavy-lifting in these calculations.
让一个好的日期时间库来完成这些计算中的繁重工作。
java.time
时间
You are using troublesome old date-time classes such as java.util.Calendar. These poorly-designed classes have been supplanted by the java.timeframework built into Java 8 and later. See Oracle Tutorial. Much of the java.time functionality has been back-ported to Java 6 & 7 in ThreeTen-Backportand further adapted to Android in ThreeTenABP.
您正在使用麻烦的旧日期时间类,例如java.util.Calendar. 这些设计不佳的类已被Java 8 及更高版本中内置的java.time框架所取代。请参阅Oracle 教程。多的java.time功能已被后移植到Java 6和7在ThreeTen-反向移植和在进一步适于到Android ThreeTenABP。
ChronoUnit
ChronoUnit
The ChronoUnitclass calculates elapsed time such as number of whole weeks between a pair of LocalDate(date-only, no time-of-day nor time zone) values.
所述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 );
Dump to console.
转储到控制台。
System.out.println ( "start: " + start + " | stop: " + stop + " | weeks: " + weeks );
start: 2016-01-01 | stop: 2016-01-18 | weeks: 2
开始: 2016-01-01 | 停站:2016-01-18 | 周数:2
If you want a number of weeks since 1989-12-31, use that as the startobject seen above.
如果您想要自 以来的数周1989-12-31,请将其用作start上面看到的对象。
LocalDate start = LocalDate.of( 1989 , 12 , 31 );
Half-Open
半开
But I notice your base date is the last day of the year. Tip: spans of time are generally best handled with the Half-Open approach where the beginning is inclusivewhile the ending is exclusive. So you maywant to use 1990-01-01as your base date (I do not know your business logic, so just a guess on my part).
但我注意到你的基准日期是一年的最后一天。提示:时间跨度通常最好使用半开方法处理,其中开头是包容性的,而结尾是独占性的。所以你可能想用1990-01-01作为你的基准日期(我不知道你的业务逻辑,所以只是我的猜测)。
So you first two weeks would be this (1st - 15th):
所以你的前两周是这样的(1st - 15th):
long firstTwoWeeks = ChronoUnit.WEEKS.between ( LocalDate.of ( 1990 , 1 , 1 ) , LocalDate.of ( 1990 , 1 , 15 ) );
…rather than this (31st - 14th):
......而不是这个(第 31 - 14 日):
long firstTwoWeeks = ChronoUnit.WEEKS.between ( LocalDate.of ( 1989 , 12 , 31 ) , LocalDate.of ( 1990 , 1 , 14 ) );

