java时间差输出负值和错误值

时间:2018-10-05 19:28:10

标签: java time simpledateformat duration

我尝试了以下代码。 当开始时间和结束时间之间存在小时/日期差时,java时间差输出负值和错误值

    Date d3 = null;
    Date d4 = null;
    List<String> activeTimeList = new ArrayList();
    int c = Integer.parseInt(cycle.get("Cycle No:").toString());
    try {
        for(int i = 0; i<c;i++) {
            SimpleDateFormat format = new SimpleDateFormat("MM-dd-yyyy HH:mm", Locale.US); //("MM/dd/yyyy HH:mm:ss");
            format.setTimeZone(TimeZone.getTimeZone("GMT"));
            String cycleEndTm = cycle.get("End Time"+i+"").toString().trim();
            String cycleStartTm = cycle.get("Start Time"+i+"").toString().trim();

            d3 = format.parse(cycleEndTm);
            d4 = format.parse(cycleStartTm);
            long diff =  d3.getTime() - d4.getTime();
            long diffSeconds = diff / 1000 % 60;
            long diffMinutes = diff / (60 * 1000) % 60;
            long diffHours = diff / (60 * 60 * 1000) % 24;
            long diffDays = diff / (24 * 60 * 60 * 1000);
            String time1 = diffDays+"."+diffHours+"."+diffMinutes+"."+diffSeconds;

Log :
0.-10.-7.0

d4 = 02-11-2017 16:47
d3 = 02-11-2017 17:27差异= 0.-10.-7.0 无法获得正确的时差?我在这里想念的是什么? 注意**:cycleEndTm -cycleStarttime应该给出正结果。我正在从地图中读取cycleEndTime和开始时间。那就是要求。

3 个答案:

答案 0 :(得分:2)

tl; dr

使用现代的 java.time 类,切勿Date。将任何Date转换为java.time.Instant

Duration                              // Represent a span-of-time as 24-hour days, hours, minutes, seconds, and nanoseconds.
.between(                             // Calculate elapsed time.
    javaUtilDateStart.toInstant() ,   // Convert any `java.util.Date` to `java.time.Instant`. Never use `Date`; it is a terrible class, ditto for `Calendar`. 
    javaUtilDateStop.toInstant()
)                                      // Returns a `Duration` object.
.toString()                            // Generate text in standard ISO 8601 format.

或调用to…Part方法以提取天数,小时数等。

java.time

您使用的是可怕的旧日期时间类(DateCalendarSimpleDateFormat),这些类早在几年前就被 java.time 类所取代。

Instant

很显然,您将获得一个java.util.Date对象。如果可能,请重写该代码以使用其替换java.time.Instant对象。两者都代表UTC的时刻,但是Instant的分辨率更佳,为纳秒而不是毫秒。如果不可能,请立即将Date转换为Instant。调用添加到旧类中的新转换方法。

Instant instant = myJavaUtilDate.toInstant() ;  // Convert from legacy class to modern class. Same moment in UTC, same point on the timeline.

以标准ISO 8601格式生成表示该时刻的文本。

使用UTC捕获当前时刻。

Instant now = Instant.now() ;  // Capture the current moment in UTC.

Duration

将经过时间计算为Duration对象。同样,这具有纳秒级的分辨率。

Duration d = Duration.between( instant , now ) ;

以标准ISO 8601格式生成表示经过时间的文本。

String output = d.toString() ; 

或者创建您的字符串,将“天”定义为24小时制,而不考虑日历。

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

String output = days + "." + hours + "." + minutes + "." + seconds ;

解析字符串

您的问题不清楚您的输入内容。如果以字符串开头,则进行解析。首先,如果可能,请更改这些字符串的源,以使用明智定义的ISO 8601标准格式。如果可能的话,请定义一个格式化模式以匹配输入。

String inputStart = "02-10-2018 10.30";

DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MM-uuuu HH.mm" );

将您的输入解析为LocalDateTime,因为它没有任何时区或自UTC偏移的指示。

LocalDateTime ldtStart = LocalDateTime.parse( inputStart , f ) ;

LocalDateTime不是不是时刻,不是表示时间轴上的一个点。此类表示大约26-27小时(全球时区范围)内的潜在时刻。

分配该字符串源所要使用的区域或偏移量,以提供确定力矩所需的上下文。

continent/region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用2-4个字母的缩写,例如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

// Transform the indefinite `LocalDateTime` to a definite moment by assigning the time zone intended by that input string.
ZoneId z = ZoneId.of( "Africa/Tunis" );
ZonedDateTime zdtStart = ldtStart.atZone( z );

计算您的时间跨度。

Duration d = Duration.between( zdtStart , zdtStop ) ;

关于 java.time

java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

在哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

答案 1 :(得分:1)

java.time

此答案不能解决您提出的问题。无论如何,我建议使用现代Java日期和时间API java.time。这里的第一个版本至少需要 Java 9 。 Java 6、7和8会更进一步。

    Map<String, Object> cycle = Map.of("Cycle No:", 1, 
            "Start Time0", "02-11-2017 16:47",
            "End Time0", "02-11-2017 17:27");

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd-yyyy HH:mm", Locale.US);
    List<String> activeTimeList = new ArrayList<>();
    int c = Integer.parseInt(cycle.get("Cycle No:").toString());
    try {
        for(int i = 0; i < c; i++) {
            String cycleEndTm = cycle.get("End Time" + i).toString().trim();
            String cycleStartTm = cycle.get("Start Time" + i).toString().trim();

            LocalDateTime d4 = LocalDateTime.parse(cycleStartTm, formatter);
            LocalDateTime d3 = LocalDateTime.parse(cycleEndTm, formatter);

            Duration diff = Duration.between(d4, d3);
            String time1 = String.format(Locale.US, "%d.%d.%d.%d", 
                    diff.toDays(), diff.toHoursPart(), 
                    diff.toMinutesPart(), diff.toSecondsPart());

            activeTimeList.add(time1);
        }
        System.out.println(activeTimeList);
    } catch (DateTimeParseException dtpe) {
        System.err.println(dtpe);
    }

此打印:

  

[0.0.40.0]

我用于格式化的toXxxPart类的Duration方法不在 Java 8 中。因此,如果您使用的是Java 8,则可以使用这种方式进行格式化:

            long days = diff.toDays();
            diff = diff.minusDays(days);
            long hours = diff.toHours();
            diff = diff.minusHours(hours);
            long minutes = diff.toMinutes();
            diff = diff.minusMinutes(minutes);
            long seconds = diff.getSeconds();
            String time1 = String.format(Locale.US, "%d.%d.%d.%d", 
                    days, hours, minutes, seconds);

输出与以前相同。

如果一起阅读的任何人正在使用 Java 6或7 ,请获取the ThreeTen Backport library,并且Java 8代码也应该在那里使用。

您的代码出了什么问题?

您发布的代码中唯一的问题是您使用的是过时的,设计不佳的日期和时间类DateSimpleDateFormatTimeZone。您的代码中没有任何内容可以解释您是如何得到错误的负值,因此我怀疑您没有在解析您认为自己在解析的字符串。

答案 2 :(得分:0)

您可以使用 java.time.Duration,它以 ISO-8601 standards 为模型,并作为 JSR-310 implementation 的一部分与 Java-8 一起引入。 Java-9 引入了一些更方便的方法。

演示:

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String d4 = "02-11-2017 16:47";
        String d3 = "02-11-2017 17:27";

        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd-MM-uuuu HH:mm", Locale.ENGLISH);

        // The given date-times in UTC
        OffsetDateTime odtD4 = LocalDateTime.parse(d4, dtf).atOffset(ZoneOffset.UTC);
        OffsetDateTime odtD3 = LocalDateTime.parse(d3, dtf).atOffset(ZoneOffset.UTC);

        // Duration between the date-times in UTC
        Duration duration = Duration.between(odtD4, odtD3);
        System.out.println(duration);    
        
        // Custom format
        // ####################################Java-8####################################
        String formattedDuration = String.format("%02d.%02d.%02d.%02d", duration.toDays(), duration.toHours() % 24,
                duration.toMinutes() % 60, duration.toSeconds() % 60);
        System.out.println(formattedDuration);
        // ##############################################################################

        // ####################################Java-9####################################
        formattedDuration = String.format("%02d.%02d.%02d.%02d", duration.toDaysPart(), duration.toHoursPart(),
                duration.toMinutesPart(), duration.toSecondsPart());
        System.out.println(formattedDuration);
        // ##############################################################################
    }
}

输出:

PT40M
00.00.40.00
00.00.40.00

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