简体   繁体   English

如何确定Java之间的现在和任意未来日期之间的时间

[英]How to determine the time between now and an arbitrary future date in Java

I'm currently trying to determine the amount of time between two dates (one of which is the present date/time, the other an arbitrary future date). 我目前正在尝试确定两个日期之间的时间量(其中一个是当前日期/时间,另一个是任意未来日期)。 I'm using native Java and the Android API only, but I'm having a few problems with GregorianCalendar. 我只使用原生Java和Android API,但我遇到GregorianCalendar的一些问题。 My code so far can be seen below, but the problem I'm having is that the time between the two dates is massively inaccurate. 到目前为止,我的代码可以在下面看到,但我遇到的问题是两个日期之间的时间非常不准确。 As you'll be able to see I've set the future date as Christmas day in this example, but it's telling me there's over 62 days until then, which is clearly wrong. 你可以看到我在这个例子中将未来的日期设定为圣诞节,但它告诉我在那之前有超过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;

While debugging I added date.set(2011, 11, 23, 13, 1, 15); 调试时我添加了date.set(2011,11,23,13,1,15); which was much more accurate, but it still displayed 32 days when I believe the correct amount of days is 31. 哪个更准确,但是当我相信正确的天数是31天时它仍然显示32天。

Thanks very much in advance for any help, much appreciated. 非常感谢您的任何帮助,非常感谢。

the problem in your code is the method calendar.set(2011, 12, 25, 0, 0, 0); 您的代码中的问题是方法calendar.set(2011, 12, 25, 0, 0, 0); what you want is calendar.set(2011, 11, 25, 0, 0, 0); 你想要的是calendar.set(2011, 11, 25, 0, 0, 0);

you can use Calendar.DECEMBER too. 你也可以使用Calendar.DECEMBER

The javadoc is clear for this method: javadoc对于这种方法很清楚:

  • @param month the value used to set the MONTH calendar field. @param month用于设置MONTH日历字段的值。 * Month value is 0-based. *月值基于0。 eg, 0 for January. 例如,1月份为0。

java.time java.time

The new java.time framework built into Java 8 and later supplants the old confusing java.util.Date/.Calendar classes Java 8及更高版本中内置的新java.time框架取代了旧的令人困惑的java.util.Date/.Calendar类

The Tutorial demonstrates how to get a span of time defined as a total number of days as well as a Period, a logical number of years and months and days. 教程演示了如何将一段时间定义为总天数以及期间,逻辑年数,月数和天数。

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

The code produces output similar to the following: 代码生成类似于以下内容的输出:

You are 53 years, 4 months, and 29 days old. 你有53岁零4个月29天。 (19508 days total) (总共19508天)

I would improve on the Tutorial's example by passing a time zone to the now rather than relying implicitly on the JVM's current default time zone which can change at any moment. 我会通过将时区传递给now来改进Tutorial的示例,而不是隐含地依赖于JVM当前的默认时区,该时区可以随时改变。 While a LocalDate has no time zone assigned (that's what local means), in determining the date a time zone is crucial. 虽然LocalDate没有分配时区(这就是本地的意思),但在确定时区是至关重要的。 For example, a new day dawns earlier in Paris than in Montréal. 例如,巴黎的新日早些时候比蒙特利尔早。

ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneId );

To get days until next birthday, construct a future date by substituting the year. 要获得直到下一个生日的日子,请通过替换年份来构建未来日期。 The Java.time framework uses immutable objects, so this syntax shown creates a new object based on the values of the original while leaving the original intact and unaffected. Java.time框架使用不可变对象,因此显示的语法基于原始值创建新对象,同时保持原始完整且不受影响。

LocalDate birthdayThisYear = birthday.withYear( today.getYear() );
if ( birthdayThisYear.isBefore( today ) ) {
    birthdayThisYear.plusYears( 1 );
}
long daysUntilBirthday = ChronoUnit.DAYS.between( today , birthdayThisYear );

Joda-Time 乔达时间

The Joda-Time library provided the inspiration for java.time. Joda-Time库为java.time提供了灵感。 Use Joda-Time when Java 8 technology is not available such as in Android. 当Java 8技术不可用时使用Joda-Time,例如在Android中。 For Android specifically you may find special builds of Joda-Time from other sources to mediate some slow loading problem in Dalvik. 对于Android,你可以从其他来源找到Joda-Time的特殊版本来调解Dalvik中的一些缓慢加载问题。

In this case the code is similar between Joda-Time and java.time. 在这种情况下,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 also offers a Period class. Joda-Time还提供Period类。 However this class handles partial days whereas java.time Period is whole days only. 但是,此类处理部分天,而java.time Period仅处理整天。 So we need to convert our LocalDate instances to DateTime instances to feed into the Period constructor. 因此,我们需要将LocalDate实例转换为DateTime实例以提供给Period构造函数。

DateTime start = today.toDateTimeAtStartOfDay( zone );
DateTime stop = nextBirthday.toDateTimeAtStartOfDay( zone );
Period period = new Period( start , stop );

The default formatter uses ISO 8601 standard formats. 默认格式化程序使用ISO 8601标准格式。 So calling period.toString() renders something like this for three months and two days: 因此,调用period.toString()这样的内容呈现三个月和两天:

P3M2D

Instead of doing this : 而不是这样做:

 long x = difference / 1000;
seconds = x % 60;
x /= 60;
minutes = x % 60;
x /= 60;
hours = x % 24;
x /= 24;
days = x;

build a Date object with the difference between the two dates (long value). 使用两个日期之间的差异(长值)构建一个Date对象。 Then you can do a setDate(Date) on a Calendar object and parse it. 然后,您可以在Calendar对象上执行setDate(Date)并解析它。

Alternatively, you can take a look at the Joda Time Api, which is relatively easy to use. 或者,你可以看一下相对容易使用的Joda Time Api。

First I suggest you use library methods for the calculations. 首先,我建议您使用库方法进行计算。 For one thing, you should not reinvent the wheel. 首先,你不应该重新发明轮子。 Second, some of the calculations may get tricky, for example if you also want to report months or years and need to take different month lengths and leap years into account. 其次,一些计算可能会变得棘手,例如,如果您还想报告数月或数年,并且需要考虑不同的月份长度和闰年。 Not least, while it's easy to divide by 60 for converting from seconds to minutes while writing the code, while reading it a method name that has 'minutes' or 'seconds' in it will more clearly convey why you are dividing by 60. 尤其是,虽然在编写代码时很容易将60除以从秒转换为分钟,但在读取代码时,其中包含“分钟”或“秒”的方法名称将更清楚地表达为什么要除以60。

These days Java has two classes for amounts of time: 这些天Java有两个类的时间量:

  • Duration is for time between clock times, for example 2 hours 46 minutes 30 seconds (it can handle days too, but knows neither weeks nor months). Duration是指时钟时间之间的时间,例如2小时46分30秒(它也可以处理数天,但不知道数周或数月)。
  • Period is for time between dates, for example 2 months 9 days. Period是指日期之间的时间,例如2个月9天。

For a general solution I will show how you may use both for your task. 对于一般解决方案,我将展示如何将两者用于您的任务。 I first find the Period between the dates. 我第一次发现Period之间的日期。 If that is from today at 2 PM to the day after tomorrow at 10 AM, you will get two days where we wanted 1 day 20 hours, so we need to adjust for that by subtracting 1 day before calculating the Duration . 如果那是从今天下午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();
    }

This prints 这打印

1 years 20 days 5 minutes 20 seconds

By using LocalDateTime I am ignoring changes to and from summer time (DST). 通过使用LocalDateTime我忽略了夏令时(DST)的变化。 If you need to take these into account, just use ZonedDateTime instead. 如果您需要考虑这些因素,请使用ZonedDateTime

All the classes are in the java.time package. 所有类都在java.time包中。 I will include a link to the Oracle tutorial at the bottom. 我将在底部包含指向Oracle教程的链接。

If you want to use java.time on Android, you get them in the ThreeTenABP. 如果你想在Android上使用java.time ,你可以在ThreeTenABP中获得它们。 More links below. 以下更多链接。

With Java 9 will come some new methods in Duration , toHoursPart() , toMinutesPart() and toSecondsPart() that will give us the hours, minutes and seconds we want, much the way I have already done with Period . 使用Java 9将在DurationtoHoursPart()toMinutesPart()toSecondsPart()中提供一些新方法,它们将为我们提供我们想要的小时,分​​钟和秒,就像我已经使用Period完成的那样。 Then we will no longer need to subtract first the hours and then the minutes while calculating the indivivual fields. 然后我们将不再需要在计算单个字段时先减去小时数然后再减去分钟数。

Links 链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 日期和现在之间的Java时间 - Java Time between Date and Now Java中当前时间和未来时间之间的时差 - Difference between current time and future time in java 如何确定特定时间的周五和周日之间的日期 - How to determine a date in between Friday and Sunday of the week at a particular time Java Date对象显示未来时间 - Java Date object shows time in the future 确定 Java 中两天之间一天发生的次数 - Determine how many time a Day occurs between two days in Java Java:生成一个范围之间的随机日期(从当前日期/时间到随机未来日期的范围(例如,从当前日期/时间开始的5-10天) - Java: Generate a random date between a range (range starting from current date/time to a random future date (e.g 5-10 days from current date/time) 问题在java中获取未来日期和当前日期之间的天数差异 - Issue getting the days difference between future date and current date in java 如何使用数学计算显示未来的日期和时间? - How to display future date and time with a math calculation? 如何以面向未来的方式获取 Java 中特定于区域设置的日期/时间模式 - How to get locale specific Date/Time patterns in Java in a future-proof way 使用Joda,如何确定给定日期是否在时间x和比x早3小时的时间之间? - Using Joda, How do I determine if a given date is between time x and a time 3 hours earlier than x?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM