我目前正在尝试确定两个日期之间的时间量(其中一个是当前日期/时间,另一个是任意的未来日期)。我只使用原生Java和Android API,但我遇到GregorianCalendar的一些问题。到目前为止,我的代码可以在下面看到,但我遇到的问题是两个日期之间的时间非常不准确。你可以看到我在这个例子中将未来的日期设定为圣诞节,但它告诉我在那之前有超过62天,这显然是错误的。
date = new GregorianCalendar();
currentTime = date.getTimeInMillis();
calendar = new GregorianCalendar();
calendar.set(2011, 12, 25, 0, 0, 0);
long difference = calendar.getTimeInMillis()-currentTime;
long x = difference / 1000;
seconds = x % 60;
x /= 60;
minutes = x % 60;
x /= 60;
hours = x % 24;
x /= 24;
days = x;
调试时我添加了date.set(2011,11,23,13,1,15);这更准确,但是当我相信正确的天数是31时,它仍然显示32天。
非常感谢您提供任何帮助,非常感谢。
答案 0 :(得分:2)
代码中的问题是方法calendar.set(2011, 12, 25, 0, 0, 0);
你想要的是calendar.set(2011, 11, 25, 0, 0, 0);
您也可以使用Calendar.DECEMBER
。
javadoc对于这种方法很清楚:
- @param month用于设置
MONTH
日历的值 领域。 *月值基于0。例如,0表示1月。
答案 1 :(得分:1)
而不是这样做:
long x = difference / 1000;
seconds = x % 60;
x /= 60;
minutes = x % 60;
x /= 60;
hours = x % 24;
x /= 24;
days = x;
使用两个日期之间的差异(长值)构建一个Date对象。然后,您可以在Calendar对象上执行setDate(Date)并解析它。
或者,你可以看一下相对容易使用的Joda Time Api。
答案 2 :(得分:1)
Java 8及更高版本中内置的新java.time框架取代了旧的令人困惑的java.util.Date/.Calendar类
Tutorial演示了如何将时间跨度定义为总天数以及期间,逻辑年数,月数和天数。
LocalDate today = LocalDate.now();
LocalDate birthday = LocalDate.of(1960, Month.JANUARY, 1);
Period p = Period.between(birthday, today);
long p2 = ChronoUnit.DAYS.between(birthday, today);
System.out.println("You are " + p.getYears() + " years, " + p.getMonths() +
" months, and " + p.getDays() +
" days old. (" + p2 + " days total)");
代码生成类似于以下内容的输出:
你是53岁零4个月29天。 (总共19508天)
我会通过将时区传递给now
来改进Tutorial的示例,而不是隐含地依赖于JVM当前的默认时区,该时区可以随时更改。虽然LocalDate没有分配时区(这就是本地的意思),但在确定时区是至关重要的。例如,巴黎的新日早些时候比蒙特利尔早了。
ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneId );
要获得直到下一个生日的日子,请通过替换年份来构建未来日期。 Java.time框架使用不可变对象,因此显示的语法基于原始值创建一个新对象,同时保持原始完整且不受影响。
LocalDate birthdayThisYear = birthday.withYear( today.getYear() );
if ( birthdayThisYear.isBefore( today ) ) {
birthdayThisYear.plusYears( 1 );
}
long daysUntilBirthday = ChronoUnit.DAYS.between( today , birthdayThisYear );
Joda-Time库为java.time提供了灵感。当Java 8技术不可用时使用Joda-Time,例如在Android中。对于Android,你可以从其他来源找到Joda-Time的特殊版本来调解Dalvik中的一些缓慢加载问题。
在这种情况下,Joda-Time和java.time之间的代码类似。
DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
LocalDate today = LocalDate.now( zone );
LocalDate birthdate = new LocalDate( 1966 , 1 , 2 );
LocalDate nextBirthday = birthdate.withYear( today.getYear() );
if ( nextBirthday.isBefore( today ) ) {
nextBirthday = nextBirthday.plusYears( 1 );
}
int daysUntilBirthday = Days.daysBetween( today , nextBirthday ).getDays();
Joda-Time还提供Period类。但是,此类处理部分天,而java.time Period仅处理整天。因此,我们需要将LocalDate实例转换为DateTime实例以提供给Period构造函数。
DateTime start = today.toDateTimeAtStartOfDay( zone );
DateTime stop = nextBirthday.toDateTimeAtStartOfDay( zone );
Period period = new Period( start , stop );
默认格式化程序使用ISO 8601标准格式。因此,调用period.toString()
会将此类内容呈现三个月零两天:
P3M2D
答案 3 :(得分:0)
首先,我建议您使用库方法进行计算。首先,你不应该重新发明轮子。其次,一些计算可能会变得棘手,例如,如果您还想报告数月或数年,并且需要考虑不同的月份长度和闰年。尤其是,当写代码时,将秒数转换为分钟很容易除以60,而读取时,它的方法名称为“分钟”或“秒”在其中将更清楚地传达为什么你要除以60。
这些天Java有两个类的时间量:
Duration
用于时钟时间之间的时间,例如2小时46分30秒(它也可以处理数天,但不知道数周或数月)。Period
用于表示日期之间的时间,例如2个月9天。对于一般解决方案,我将展示如何将两者用于您的任务。我首先在日期之间找到Period
。如果是从今天下午2点到后天上午10点,你将得到两天我们想要1天20小时,所以我们需要在计算Duration
之前减去1天来调整。
LocalDateTime dateTimeOne = LocalDateTime.of(2016, Month.APRIL, 25, 9, 5, 30);
LocalDateTime dateTimeTwo = LocalDateTime.of(2017, Month.MAY, 15, 9, 10, 50);
Period p = Period.between(dateTimeOne.toLocalDate(), dateTimeTwo.toLocalDate());
LocalDateTime dtOnePlusPeriod = dateTimeOne.plus(p);
if (dtOnePlusPeriod.isAfter(dateTimeTwo)) { // too far
p = p.minusDays(1);
}
Duration d = Duration.between(dateTimeOne.plus(p), dateTimeTwo);
long hours = d.toHours();
d = d.minusHours(hours);
long minutes = d.toMinutes();
d = d.minusMinutes(minutes);
long seconds = d.getSeconds();
if (p.isZero() && d.isZero()) {
System.out.println("0 seconds");
} else {
if (p.getYears() != 0) {
System.out.print("" + p.getYears() + " years ");
}
if (p.getMonths() != 0) {
System.out.print("" + p.getMonths() + " months ");
}
if (p.getDays() != 0) {
System.out.print("" + p.getDays() + " days ");
}
if (hours != 0) {
System.out.print("" + hours + " hours ");
}
if (minutes != 0) {
System.out.print("" + minutes + " minutes ");
}
if (seconds != 0) {
System.out.print("" + seconds + " seconds");
}
System.out.println();
}
打印
1 years 20 days 5 minutes 20 seconds
使用LocalDateTime
我忽略夏令时(DST)的变化。如果您需要考虑这些因素,请改用ZonedDateTime
。
所有类都在java.time
包中。我将在底部包含指向Oracle教程的链接。
如果您想在Android上使用java.time
,可以在ThreeTenABP中获取它们。以下更多链接。
使用Java 9将在Duration
,toHoursPart()
,toMinutesPart()
和toSecondsPart()
中提供一些新方法,它们将为我们提供我们想要的小时,分钟和秒,我已经完成了Period
的方式。然后我们将不再需要在计算单个字段时先减去小时数然后再减去分钟数。