繁体   English   中英

Java时间计算

[英]Java Time calculation

所以我的方法接收24小时格式的时间(“HH:MM:SS”)并返回一个字符串差异时间。 如果是当地时间下午2:00我应该能够“16:30:00”(下午4:30)发送它并输出“2小时30分钟”。 但代码有一些问题,我只是一个初学者,我需要帮助来解决它。

问题是如果时间是下午4:40,我发送它“17:00:00”(下午5:00)它返回消息:12小时20分钟而不是0小时20分钟。 另一个问题是,如果我发送当前时间,它将返回“12小时”,而不是像它应该的那样24。

请记住,我只是java的初学者,数学真的不是我的事,所以任何帮助都非常感谢。 谢谢。

private static String timeUntil(String distanceTime) {
String returnMsg = null;
try {
    SimpleDateFormat sdfDate = new SimpleDateFormat("hh:mm:ss");
    Date now = new Date();
    java.text.DateFormat df = new java.text.SimpleDateFormat("hh:mm:ss");
    Date date1 = df.parse(sdfDate.format(now));
    Date date2 = df.parse(distanceTime);
    long diff = date2.getTime() - date1.getTime();
    int timeInSeconds = (int) (diff / 1000);
    int hours, minutes;

    hours = timeInSeconds / 3600;
    timeInSeconds = timeInSeconds - (hours * 3600);
    minutes = timeInSeconds / 60;

    if (hours >= 0) {
    returnMsg = hours + " hours" +
            "\n" + minutes + " mins";
    } else {
    returnMsg = minutes + " mins";
    }
} catch (Exception e) {
    e.printStackTrace();
}
return returnMsg;
}

在您的日期格式中, hh用于12小时。 使用HH 24小时:

new SimpleDateFormat("HH:mm:ss");

代码审查评论......

  1. 大多数Date类的方法都已弃用。 您应该考虑使用Calendar(GregorianCalendar)而不是Date。

  2. 您的变量名称通常缺乏意义 - 您必须知道变量的目的才能知道其含义。 如果使用更好的变量名,您的代码将更易于维护。 df可以重命名为“format”或“dateFormat”。

  3. 您现在创建一个Date对象,然后通过您的df DateFormat实例传递它,通过您的sdfDate实例,将其转换回Date。 这是不必要的。 将其替换为Date date1 = new Date(); 并立即删除Date now = new Date(); 同时,我看到在单位之间进行转换时很难诊断出错误,所以你应该改变diff以表明它是毫秒,就像diff_ms一样。 你应该保持名称一致 - 你从“不同”( diff )变为“timeInSeconds”。 它们都应该是“timeInXxx”或“diff_xx”。 distanceTime参数应该重命名为futureTime

  4. 你做了一堆数学来确定两次之间的差异,但有些库会为你做这件事。 谷歌为“两个日期之间的java差异”找到了很多答案。

  5. 您的代码始终假定第二次出现在“now”之后。 这应该包含在方法顶部的注释中。

  6. 当您实例化date1和date2时,它们可能都在同一天。 尝试调试或至少在创建对象后立即将对象打印到stdout以查看是否是这种情况。 这是你真正想要的吗?

  7. 您的代码不处理闰年。

  8. 而不是自己处理所有的时间转换,为什么不寻找适合您的库?

这是你的固定代码。 我已将日期格式更改为HH:mm:ss以及您的计算逻辑。 试一试,告诉我们

private static String timeUntil(String distanceTime) {
    String returnMsg = null;
    try {
        SimpleDateFormat sdfDate = new SimpleDateFormat("HH:mm:ss");
        Date now = new Date();
        java.text.DateFormat df = new java.text.SimpleDateFormat("HH:mm:ss");
        Date date1 = df.parse(sdfDate.format(now));
        Date date2 = df.parse(distanceTime);
        long diff = date2.getTime() - date1.getTime();
        int timeInSeconds = (int) (diff / 1000);
        int hours, minutes;

        hours = timeInSeconds / 3600;
        timeInSeconds = timeInSeconds - (hours * 3600);
        minutes = timeInSeconds / 60;

        if (hours != 0) {
        returnMsg = hours + " hours" +
                "\n" + minutes + " mins";
        } else {
        returnMsg = minutes + " mins";
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return returnMsg;
    }

这是一个更健壮的例子,并使用Java更现代的日期函数。 我可以一点一点地指出你可以在你的例子中做得更好的事情,但有时它更容易给你一个很好的例子,让你从其他人的代码中收集你所能做的好的风格。

import java.util.Calendar;

public class testSpace {
     public static void main (String ... args){
            System.out.println(timeUntil("00:12:12"));      
    }

    private static String timeUntil(String distanceTime){

        String[] times = distanceTime.split(":");

        Calendar now = Calendar.getInstance();

        Calendar then = Calendar.getInstance();
        then.set(Calendar.SECOND, Integer.parseInt(times[2]));
        then.set(Calendar.MINUTE, Integer.parseInt(times[1]));
        then.set(Calendar.HOUR, Integer.parseInt(times[0]) % 12);
        then.set(Calendar.AM_PM,  (Integer.parseInt(times[0]) >= 12 ) ? Calendar.PM : Calendar.AM);

        boolean isFuture = (then.getTimeInMillis() > now.getTimeInMillis());

        long interval = (isFuture)
            ? then.getTimeInMillis() - now.getTimeInMillis()
            : now.getTimeInMillis() - then.getTimeInMillis();

        return ((isFuture) ? "" : "-") + millToTime(interval);
    }

    public static long MILLISECOND_PER_HOUR = 1000*60*60;
    public static long MILLISECOND_PER_MIN = 1000*60;
    public static long MILLISECOND_PER_SECOND = 1000;

    public static String millToTime(long mill){
        long hours  = mill / MILLISECOND_PER_HOUR;
        long mins   = (mill % MILLISECOND_PER_HOUR) / MILLISECOND_PER_MIN;
        long sec    = ((mill % MILLISECOND_PER_HOUR) % MILLISECOND_PER_MIN) / MILLISECOND_PER_SECOND;
        return String.format("%d:%d:%d", hours, mins, sec);
    }
}

TL;博士

仅适用于时间,没有日期或时区。

LocalTime start = LocalTime.of( "16:40" ) ;
LocalTime stop = LocalTime.of( "17:00" ) ;
Duration d = Duration.between( start , stop ) ;

PT20M

或者,对于区域中的日期时间。

ZoneId z = ZoneId.of( "America/Montreal" )
ZonedDateTime zdtNow = ZonedDateTime.now( z );
ZonedDateTime zdtThen = 
    ZonedDateTime.of(   // Pass a LocalDate, LocalTime, ZoneId.
        zdtNow.toLocalDate() ,  // Same date…
        LocalTime.parse( "16:30:00" ) ,  // … but different time-of-day.
        z  
    ) 
Duration d = Duration.between( zdtNow , zdtThen ) ;

PT2H30M

细节

您正在使用旧的日期时间类,现在是旧的,由java.time类取代。

LocalTime

您错误地将日期时间类用于仅限时间的值。 而是使用LocalTime类。 并在计算经过时间时使用时间跨度类。

String input = "16:30:00" ;
LocalTime lt = LocalTime.parse( input );

Instant

Instant类表示UTC时间轴上的一个时刻,分辨率为纳秒 (最多九(9)位小数)。

Instant instant = Instant.now();

ZonedDateTime

确定挂钟时间需要一个时区。 continent/region的格式指定适当的时区名称 ,例如America/MontrealAfrica/CasablancaPacific/Auckland 切勿使用3-4字母缩写,例如ESTIST因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtNow = instant.atZone( z );  // Adjusted into your time zone.

现在为您指定的输入时间构建ZonedDateTime

ZonedDateTime zdtTarget = ZonedDateTime.of( zdtNow.toLocalDate() , lt , z );

Duration

使用Duration表示未附加到时间线的已用时间。

Duration d = Duration.between( zdtNow , zdtTarget );

请注意,如果指定的时间早于当前时间,则持续时间将为负数。

持续时间为ISO 8601字符串

要获取描述该时间跨度的小时,分​​钟等的字符串,只需调用toString以标准ISO 8601格式生成PnYnMnDTnHnMnS的字符串,其中P标记开头, T将年 - 月 - 日与小时 - 分钟分开-seconds。

如果同一区域的当前时间是14:00:00 ,则输出为:

PT2H30M

吸气方法

奇怪的是,在Java 8中,这个类Duration缺少任何部件的getter方法,例如2小时和30分钟。 使用 toHoursParttoMinutesPart方法在Java 9中进行了 toMinutesPart


关于java.time

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

现在处于维护模式Joda-Time项目建议迁移到java.time。

要了解更多信息,请参阅Oracle教程 并搜索Stack Overflow以获取许多示例和解释。 规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。 该项目是未来可能添加到java.time的试验场。 您可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter ,和更多

暂无
暂无

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

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