繁体   English   中英

如何在两个Calendar对象之间转换确切的时间量(年,月,日,小时,分钟,秒)?

[英]How would I convert the exact amount of time (years, months, days, hours, minutes, seconds) between two Calendar objects?

我试图隐瞒Java中两个Calendar对象之间的确切时间。

这是我目前拥有的代码...

public static Map<TimeUnit, Long> computeDifference(Calendar date1, Calendar date2) { 

    long diffInMillies = date2.getTimeInMillis() - date1.getTimeInMillis();

    //create the list
    List<TimeUnit> units = new ArrayList<TimeUnit>();
    units.add(TimeUnit.SECONDS);
    units.add(TimeUnit.MINUTES);
    units.add(TimeUnit.HOURS);
    units.add(TimeUnit.DAYS);
    Collections.reverse(units);

    //create the result map of TimeUnit and difference
    Map<TimeUnit,Long> result = new LinkedHashMap<TimeUnit,Long>();
    long milliesRest = diffInMillies;

    for ( TimeUnit unit : units ) {

        //calculate difference in millisecond 
        long diff = unit.convert(milliesRest,TimeUnit.MILLISECONDS);
        long diffInMilliesForUnit = unit.toMillis(diff);
        milliesRest = milliesRest - diffInMilliesForUnit;

        //put the result in the map
        result.put(unit,diff);
    }

    return result;
}   

打印时,对于输入date1 = 19 August 2019 02:00:00date2 = 20 August 2019 12:30:45 ,输出看起来像这样{DAYS=1, HOURS=10, MINUTES=30, SECONDS=45}

此方法中可用的最大时间单位是DAYS ,但是我想找到包含月份和年份的东西。 我意识到TimeUnit与特定的日历日期(实际上是24小时间隔)并没有任何关系,这就是为什么我想知道是否有任何方法可以使用Calendar类或类似的方法进行这种转换。 我还研究了ChronoUnit作为TimeUnit的替代品,但由于TimeUnit不能使用的相同原因而无法使用。

希望有任何有关如何合并较大时间单位的建议。 谢谢!

您不应该使用Calendar类,因为它已经过时了。 您应该改用java.time包中的类。

为了获得所需的结果,可以使用Period类。

您首先需要将两个Calendar实例都转换为LocalDate实例

然后,您可以使用Period.between(startDate, endDate)获得一个Period实例,该实例使getDays()getMonths()getYears()方法可用。


如果您还想包括时间部分(小时,分钟和秒),则可以将DurationPeriod结合使用。 但首先阅读由Sweeper链接的帖子

这样的事情可能会起作用:

LocalDateTime start = LocalDateTime.of(2019, 1, 1, 12, 0, 0);
LocalDateTime end = LocalDateTime.of(2021, 4, 26, 5, 56, 40);

Duration d = Duration.between(start.toLocalTime(), end.toLocalTime());
Period p = Period.between(start.toLocalDate(), end.toLocalDate());

// If the startdate's time component lies behind the enddate's time component,
// then we need to correct both the Period and Duration
if (d.isNegative()) {
    p = p.minusDays(1);
    d = d.plusDays(1);
}

System.out.printf("y %s m %s d %s h %s m %s s %s%n",
    p.getYears(),
    p.getMonths(),
    p.getDays(),
    d.toHours() % 24,
    d.toMinutes() % 60,
    d.getSeconds() % 60);

请注意,Java 9带有to…Part方法,因此您不必再使用模运算符。


请注意:由于夏令时,此代码未考虑时钟调整。

tl; dr

Period
.between(
    ( ( GregorianCalendar ) myCalStart ).toZonedDateTime().toLocalDate() ,
    ( ( GregorianCalendar ) myCalStop ).toZonedDateTime().toLocalDate() 
)

…要么…

Duration
.between(
    ( ( GregorianCalendar ) myCalStart ).toInstant() ,
    ( ( GregorianCalendar ) myCalStop ).toInstant() 
)

java.time

您使用的是可怕的日期时间类,而该类在几年前已被JSR 310中定义的现代java.time类所取代。

切勿使用CalendarGregorianCalendarDateSimpleDateFormat等。 仅使用java.time包中的类。

ZonedDateTime

假设您的两个Calendar对象实际上都是其下方的GregorianCalendar对象,请进行转换。 要进行转换,请to…添加到旧类的方法中调用new to… / from…方法。

// start
GregorianCalendar gcStart = ( GregorianCalendar ) myCalStart ;
ZonedDateTime zdtStart = gcStart.toZonedDateTime() ;

// stop
GregorianCalendar gcStop = ( GregorianCalendar ) myCalStop ;
ZonedDateTime zdtStop = gcStop.toZonedDateTime() ;

GregorianCalendarZonedDateTime代表一个日期,该日期中的一个时区放置在时区的上下文中,结合起来确定一个时刻(时间轴上的特定点)。 ZonedDateTime解析为更好的纳秒级别,而不是毫秒。

Period

如果您关心的是以年-月-日为单位的经过时间,则将PeriodLocalDate对象一起使用。 LocalDate表示没有日期和时区的日期。 我们可以从ZonedDateTime对象中提取日期部分。

LocalDate ldStart = zdtStart.toLocalDate() ;
LocalDate ldStop = zdtStop.toLocalDate() ;
Period p = Period.between( ldStart , ldStop ) ;

生成标准ISO 8601格式的字符串。

String output = p.toString() ;

询问数年,数月,数天。

int years = p.getYears() ;
int months = p.getMonths() ;
int days = p.getDays() ;

Duration

如果您希望以小时-分钟-秒为单位来计算经过时间,请使用Duration 此类代表了UTC中的两个时刻。 因此,我们从一对ZonedDateTime对象中提取了Instant对象,这些对象从UTC 1970年第一时刻的纪元参考开始在内部保留整秒的计数,再加上小数秒(以纳秒为单位)。

Instant instantStart = zdtStart.toInstant() ;
Instant instantStop = zdtStop.toInstant() ;
Duration d = Duration.between( instantStart , instantStop ) ;

生成标准ISO 8601格式的字符串。

String output = d.toString() ;

询问数天(与日历无关的24小时时间段),小时,分钟,秒。

long days = d.toDaysPart() ;
int hours = d.toHoursPart() ;
int minutes = d.toMinutesPart() ;
int seconds = d.toSecondsPart() ;
int nanos = d.toNanosPart() ;

PeriodDuration

如果您考虑一下,您会发现将年/月/日与24小时/天/小时/分钟/秒结合起来是没有意义的。 请参阅此堆栈溢出页面,以供深思。

但是,如果您坚持要结合这两个不同的概念,请参见在ThreeTen-Extra库中找到的PeriodDuration类。


Java中的日期时间类型表,包括现代的和传统的。

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM