简体   繁体   English

Java时间计算

[英]Java Time calculation

So my method receives a time in 24 hour format ("HH:MM:SS") and returns a string the difference time. 所以我的方法接收24小时格式的时间(“HH:MM:SS”)并返回一个字符串差异时间。 If it's 2:00PM local time I should be able to send it "16:30:00"(4:30PM) and get the output "2 hours, 30 mins". 如果是当地时间下午2:00我应该能够“16:30:00”(下午4:30)发送它并输出“2小时30分钟”。 But the code has some problem, and I am just a beginner and I need help to fix it. 但代码有一些问题,我只是一个初学者,我需要帮助来解决它。

The problem is if the time is 4:40PM, and I sent it "17:00:00"(5:00PM) it returns the message: 12 hours, 20 minutes instead of 0 hours, 20 minutes. 问题是如果时间是下午4:40,我发送它“17:00:00”(下午5:00)它返回消息:12小时20分钟而不是0小时20分钟。 The other problem is if I sent it the current time, it would return "12 hours" away, and not 24 like it should. 另一个问题是,如果我发送当前时间,它将返回“12小时”,而不是像它应该的那样24。

Please keep in mind I am only a beginner at java and math really isn't my thing, so any help is highly appreciated. 请记住,我只是java的初学者,数学真的不是我的事,所以任何帮助都非常感谢。 Thanks. 谢谢。

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;
}

In your date format, hh is used for 12 -hour time. 在您的日期格式中, hh用于12小时。 Use HH for 24 -hour time: 使用HH 24小时:

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

Code review comments... 代码审查评论......

  1. Most of the Date class' methods are deprecated. 大多数Date类的方法都已弃用。 You should consider using Calendar (GregorianCalendar) instead of Date. 您应该考虑使用Calendar(GregorianCalendar)而不是Date。

  2. Your variable names often lack meaning - you have to know the purpose of the variable to know its meaning. 您的变量名称通常缺乏意义 - 您必须知道变量的目的才能知道其含义。 Your code will be more maintainable if you use better variable names. 如果使用更好的变量名,您的代码将更易于维护。 df could be renamed "format" or "dateFormat". df可以重命名为“format”或“dateFormat”。

  3. You create a Date object 'now', then you pass it through your df DateFormat instance, hten through your sdfDate instance, to convert it back to a Date. 您现在创建一个Date对象,然后通过您的df DateFormat实例传递它,通过您的sdfDate实例,将其转换回Date。 This is unnecessary. 这是不必要的。 Replace this with Date date1 = new Date(); 将其替换为Date date1 = new Date(); and remove Date now = new Date(); 并立即删除Date now = new Date(); . Simiilarly, I've seen very difficult to diagnose errors when converting between units, so you should change diff to indicate that it's milliseconds, like diff_ms . 同时,我看到在单位之间进行转换时很难诊断出错误,所以你应该改变diff以表明它是毫秒,就像diff_ms一样。 And you should keep names consistent - you change from "different" ( diff ) to "timeInSeconds". 你应该保持名称一致 - 你从“不同”( diff )变为“timeInSeconds”。 They should both be "timeInXxx" or "diff_xx". 它们都应该是“timeInXxx”或“diff_xx”。 the distanceTime parameter should be renamed something like futureTime distanceTime参数应该重命名为futureTime

  4. You do a bunch of math to determine the difference between two times, but there are libraries that will do this for you. 你做了一堆数学来确定两次之间的差异,但有些库会为你做这件事。 Google for "java difference between two dates" and find many answers. 谷歌为“两个日期之间的java差异”找到了很多答案。

  5. Your code always assumes that the second time occurs after "now". 您的代码始终假定第二次出现在“now”之后。 This should be included in a comment at the top of your method. 这应该包含在方法顶部的注释中。

  6. When you instantiate date1 and date2, they're both probably for the same day. 当您实例化date1和date2时,它们可能都在同一天。 Try debugging or at least printing the objects to stdout immediately after they're created to see if this is the case. 尝试调试或至少在创建对象后立即将对象打印到stdout以查看是否是这种情况。 Is this what you really want? 这是你真正想要的吗?

  7. Your code doesn't handle leap year. 您的代码不处理闰年。

  8. Instead of handling all of the time conversions yourself, why don't you look for a library that does it for you? 而不是自己处理所有的时间转换,为什么不寻找适合您的库?

This is your fixed code. 这是你的固定代码。 I have changed the date format to HH:mm:ss and also your calculation logic. 我已将日期格式更改为HH:mm:ss以及您的计算逻辑。 Try it and let us know 试一试,告诉我们

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;
    }

Here is an example which is more robust and uses Java more modern date functions. 这是一个更健壮的例子,并使用Java更现代的日期函数。 I could go point by point and point at all the thing you could have done better in your example, but sometimes its easier to give you a good example and let you glean what you can from other people code as far as good style. 我可以一点一点地指出你可以在你的例子中做得更好的事情,但有时它更容易给你一个很好的例子,让你从其他人的代码中收集你所能做的好的风格。

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;dr TL;博士

For time-of-day only, without a date or time zone. 仅适用于时间,没有日期或时区。

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

PT20M PT20M

Or, for date-time in a zone. 或者,对于区域中的日期时间。

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 PT2H30M

Details 细节

You are using old date-time classes, now legacy, supplanted by the java.time classes. 您正在使用旧的日期时间类,现在是旧的,由java.time类取代。

LocalTime

You are incorrectly using a date-time class for a time-of-day-only value. 您错误地将日期时间类用于仅限时间的值。 Instead use the LocalTime class. 而是使用LocalTime类。 And use a span-of-time class when calculating elapsed time. 并在计算经过时间时使用时间跨度类。

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

Instant

The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction). Instant类表示UTC时间轴上的一个时刻,分辨率为纳秒 (最多九(9)位小数)。

Instant instant = Instant.now();

ZonedDateTime

Determining a wall-clock time requires a time zone. 确定挂钟时间需要一个时区。 Specify a proper time zone name in the format of continent/region , such as America/Montreal , Africa/Casablanca , or Pacific/Auckland . continent/region的格式指定适当的时区名称 ,例如America/MontrealAfrica/CasablancaPacific/Auckland Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!). 切勿使用3-4字母缩写,例如ESTIST因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

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

Now construct a ZonedDateTime for your given input time-of-day. 现在为您指定的输入时间构建ZonedDateTime

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

Duration

Use Duration to represent elapsed time not attached to the timeline. 使用Duration表示未附加到时间线的已用时间。

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

Note that the duration will be a negative amount if the specified time-of-day is earlier than the current time-of-day. 请注意,如果指定的时间早于当前时间,则持续时间将为负数。

ISO 8601 string for duration 持续时间为ISO 8601字符串

To get a String describing the hours, minutes, etc. of that span of time, simply call toString to generate a String in standard ISO 8601 format of PnYnMnDTnHnMnS where P marks the beginning and T separates the years-month-days from hours-minutes-seconds. 要获取描述该时间跨度的小时,分​​钟等的字符串,只需调用toString以标准ISO 8601格式生成PnYnMnDTnHnMnS的字符串,其中P标记开头, T将年 - 月 - 日与小时 - 分钟分开-seconds。

If the current time were 14:00:00 in the same zone, the output would be: 如果同一区域的当前时间是14:00:00 ,则输出为:

PT2H30M PT2H30M

Getter methods 吸气方法

Oddly, in Java 8 this class Duration lacks any getter methods for the parts such as 2 for hours and 30 for minutes. 奇怪的是,在Java 8中,这个类Duration缺少任何部件的getter方法,例如2小时和30分钟。 Remedied in Java 9 with methods such as toHoursPart and toMinutesPart . 使用 toHoursParttoMinutesPart方法在Java 9中进行了 toMinutesPart


About java.time 关于java.time

The java.time framework is built into Java 8 and later. java.time框架内置于Java 8及更高版本中。 These classes supplant the troublesome old legacy date-time classes such as java.util.Date , Calendar , & SimpleDateFormat . 这些类取代了麻烦的旧遗留日期时间类,如java.util.DateCalendarSimpleDateFormat

The Joda-Time project, now in maintenance mode , advises migration to java.time. 现在处于维护模式Joda-Time项目建议迁移到java.time。

To learn more, see the Oracle Tutorial . 要了解更多信息,请参阅Oracle教程 And search Stack Overflow for many examples and explanations. 并搜索Stack Overflow以获取许多示例和解释。 Specification is JSR 310 . 规范是JSR 310

Where to obtain the java.time classes? 从哪里获取java.time类?

The ThreeTen-Extra project extends java.time with additional classes. ThreeTen-Extra项目使用其他类扩展了java.time。 This project is a proving ground for possible future additions to java.time. 该项目是未来可能添加到java.time的试验场。 You may find some useful classes here such as Interval , YearWeek , YearQuarter , and more . 您可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter ,和更多

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

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