无法使用Java解析星期三至星期四的正确总小时数

时间:2018-08-23 07:18:15

标签: java duration date-parsing datetime-parsing java-date

解析日期和时间以获取Java的总时数和分钟数时遇到问题。

如果我计算从“星期一22:00”到“星期二22:00”开始的总时间,那么我会得到正确的总小时数24。但是,如果我计算从“星期三22:00”到当前日期的总时间,时间像“星期四12:45”,那么我得到的“小时数:-153分钟:-15”。

仅在星期三和星期四才是这种情况。在剩下的日子里,它工作正常。

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.TimeUnit;

public class Test {

    private static DateFormat dateFormat = new SimpleDateFormat("EEE HH:mm");
    private static DateFormat dayFormat = new SimpleDateFormat("E");
    private static Calendar calendar = Calendar.getInstance();

    public static void main(String[] args) {        

        try {

            Date date1 = dateFormat.parse("Wed 22:00");
            Date date2 = dateFormat.parse(dayFormat.format(calendar.getTime()) + " " + calendar.getTime().getHours() + ":"
                    + calendar.getTime().getMinutes());

            long hours2 = getDurationInHours(date1, date2);
            long min = getDurationInMin(date1, date2);

            System.out.println("Hours : " + hours2 + " Min : " + min);

        } catch (Exception e) {
            e.printStackTrace();
        }       
    }

    public static long getDurationInHours(Date returnTime, Date leaveTime) {
        long durationInMillis = leaveTime.getTime() - returnTime.getTime();
        long hours = TimeUnit.MILLISECONDS.toHours(durationInMillis);
        return hours;
    }

    public static long getDurationInMin(Date returnTime, Date leaveTime) {
        long durationInMillis = leaveTime.getTime() - returnTime.getTime();
        long min = TimeUnit.MILLISECONDS.toMinutes(durationInMillis) % 60;
        return min;
    }

}

3 个答案:

答案 0 :(得分:3)

这是因为当您将日期定义为22:00星期三时,它不是当前一周的星期三。实际上是1970年1月7日;)

您可能已经知道,java中的日期从1970年1月1日起一直是一个长整数。因此,当您说星期三而不是实际日期时,它将获得1970年之后的第一个星期三,即第七个星期三。当您说星期一22:00时,它可以正常工作,因为它使用的是1970年1月5日,并且相差2天。

当您以相同的逻辑使用“ Thu 22:00”时,它使用的是1970年1月1日(即星期四),因此您得到负数。因为实际上要提前6天

答案 1 :(得分:1)

java.time

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE H:mm", Locale.ENGLISH);

    ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/Dominica"));
    TemporalAccessor fromTa = formatter.parse("Wed 22:00");
    ZonedDateTime from = now
            .with(TemporalAdjusters.previous(DayOfWeek.from(fromTa)))
            .with(LocalTime.from(fromTa));
    Duration dur = Duration.between(from, now);
    System.out.println(dur);

现在运行此代码将给出以下输出:

  

PT11H41M25.284611S

这意味着持续11个小时41分钟25.284611秒。如果需要在程序中进一步使用此持续时间,则可能需要保留Duration对象。对于向用户打印不是很好,所以可以这样做:

    long hours = dur.toHours();
    int min = dur.toMinutesPart();
    System.out.println("" + hours + " hours " + min + " min");
  

11小时41分钟

Java没有“星期三22:00”的概念。因此,我们需要选择一个特定的星期三和一个特定的星期四。 SimpleDateFormat试图为您提供帮助并为您选择,但没有选择您期望的星期三和星期四,因此对您没有任何帮助。 java.time,现代的Java日期和时间API,迫使我们自行选择。我更喜欢这个。这样可以使代码中发生的事情更加清晰明了,从而使发现和修复错误更容易。

我对TemporalAdjusters.previous的使用可以确保我在最后星期三(不是下星期三)。我对ZonedDateTime的使用可以确保小时和分钟正确无误。即使跨夏季和夏季时间(夏令时)之间的过渡以及其他此类时间过渡。如果不是美国/多米尼加,您当然应该填写自己的时区。

链接: Oracle tutorial: Date Time解释了如何使用java.time

答案 2 :(得分:0)

java.util 的日期时间 API 及其格式化 API SimpleDateFormat 已过时且容易出错。建议完全停止使用它们并切换到 modern date-time API

您可以使用 java.time.Duration 以直观的方式完成此操作,它以 ISO-8601 standards 为模型,并作为 JSR-310 implementation 的一部分在 Java-8 中引入。 Java-9 引入了一些更方便的方法。

请注意工作日和时间,例如Mon 22:00 不足以直接创建日期时间对象。工作日星期一每周都会到来,因此我们必须创建一个默认为特定日期的日期时间对象,例如today。以此日期作为参考,您可以找到给定工作日(例如LocalDate)的第一次出现(Monday),并且从该对象中,您可以获得具有给定时间的日期时间对象。

Duration#between 为您提供两个日期时间对象之间的 Duration 对象。使用 Duration 对象,您可以创建一个按照您的要求格式化的字符串,方法是从中获取天、小时、分钟、秒。

演示:

import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjusters;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        // Test
        displayDuration(getDuration("Mon 22:00", "Tue 22:00"));
        displayDuration(getDuration("Wed 22:00", "Thu 12:45"));
    }

    static Duration getDuration(String strStartDayTime, String strEndDayTime) {
        LocalDate today = LocalDate.now();
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE HH:mm", Locale.ENGLISH);
        TemporalAccessor taStart = dtf.parse(strStartDayTime);
        TemporalAccessor taEnd = dtf.parse(strEndDayTime);

        LocalDateTime ldtStartDateTime = today.with(TemporalAdjusters.nextOrSame(DayOfWeek.from(taStart)))
                .atTime(LocalTime.from(taStart));
        LocalDateTime ldtEndDateTime = today.with(TemporalAdjusters.nextOrSame(DayOfWeek.from(taEnd)))
                .atTime(LocalTime.from(taEnd));

        return Duration.between(ldtStartDateTime, ldtEndDateTime);
    }

    static String formatDurationJava8(Duration duration) {
        return String.format("Days: %d, Hours: %02d, Minutes: %02d, Seconds: %02d", duration.toDays(),
                duration.toHours() % 24, duration.toMinutes() % 60, duration.toSeconds() % 60);
    }

    static String formatDurationJava9(Duration duration) {
        return String.format("Days: %d, Hours: %02d, Minutes: %02d, Seconds: %02d", duration.toDaysPart(),
                duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart());
    }

    static void displayDuration(Duration duration) {
        // Default format
        System.out.println(duration);
        // Custom format
        System.out.println(formatDurationJava8(duration));
        System.out.println(formatDurationJava9(duration));
    }
}

输出:

PT24H
Days: 1, Hours: 00, Minutes: 00, Seconds: 00
Days: 1, Hours: 00, Minutes: 00, Seconds: 00
PT14H45M
Days: 0, Hours: 14, Minutes: 45, Seconds: 00
Days: 0, Hours: 14, Minutes: 45, Seconds: 00

Trail: Date Time 了解现代日期时间 API。