将时间戳字符串“HH:mm:ss”转换为持续时间

4
就像标题中所说的,我已经能够在文本文件中分离出一个以“HH:mm:ss”格式表示时长的字符串。我该如何将其转换为持续时间?我需要将其转换为一个双精度数,以1小时为单位表达这个时间戳,因此如果是“08:30:00”,我需要双精度数的值为8.5。不确定如何进行转换,似乎Java中的时间是一个棘手的问题。非常感谢任何帮助,即使只是告诉我“使用这个类”,我也可以查找并弄清楚。

谢谢!


您可以使用parse方法将字符串转换为本地时间。然后使用getSecond方法并除以60以获得分钟数。接着使用getMinute方法获取分钟数,加上从秒转换的分钟数并除以60以获得小时数。然后将该值添加到时间的getHour值中即可。 另一种方法是使用冒号拆分字符串并进行类似的计算。 - Rahul Sharma
3个回答

2

简而言之

Duration.between ( 
    LocalTime.MIN , 
    LocalTime.parse ( "08:30:00" ) 
).toString()

PT8H30M

持续时间与时间戳

如果你用字符串08:30:00表示“八个半小时”时间跨度,则不要使用术语“时间戳”。正确且常用的词是“持续时间”。避免使用HH:MM:SS格式,因为它太模糊了,看起来像是一天中的时间。而应该使用下面讨论的标准格式。

如果你用字符串08:30:00表示“早上八点半”,则使用“时间戳”这个词并避免使用“持续时间”这个术语。

这是两个非常不同的概念。你必须清楚地理解它们,每个概念在你的脑海中应该是独立的。使用HH:MM:SS这种模糊的格式会使这种区别更加困难(所以避免使用这种格式!)。

java.time

现代方法是使用java.time类。

LocalTime

正如Sharma在评论中提到的那样,首先将你的字符串解析为LocalTime。这个类表示一天中的时间,没有日期和时区。没有时区意味着这些对象基于通用的24小时时钟,不考虑例如夏令时(DST)等异常情况。

我们实际上不需要一个LocalTime,因为你的输入字符串表示一个时间跨度而不是一天中的时间。但这只是第一步。

LocalTime lt = LocalTime.parse ( "08:30:00" );

持续时间

为了表示所需的时间跨度,我们需要使用Duration类。该类用于没有与时间轴相关联的时间跨度。我们可以通过从时钟开始的时间量00:00:00.0LocalTime.MIN和我们刚刚实例化的lt来创建一个时间跨度。

Duration d = Duration.between ( LocalTime.MIN , lt );

ISO 8601

我们可以通过调用Duration::toString方法生成标准的ISO 8601持续时间格式字符串来查看结果。java.time类在解析/生成字符串时默认使用ISO 8601。对于持续时间,标准格式为PnYnMnDTnHnMnS,其中P表示开始,T分隔年月日部分和时分秒部分。因此,我们的8个半小时将显示为PT8H30M

System.out.println("d.toString(): " + d);

d.toString(): PT8H30M

避免使用小数表示日期时间值

处理这样的持续时间值,我强烈建议在您的Java代码中使用Duration对象,在序列化为文本时使用ISO 8601格式。

  • 在代码中使用对象提供类型安全性、使您的代码更易于自我记录并确保有效值。
  • 在文本中使用ISO 8601格式使得数值易于解析,这是人们易于阅读的格式,并且在其含义上不像08:30:00这样的内容容易被误读为一天中的时间。

您希望使用小数表示,如8.5,是有歧义的(很容易失去其含义)。此外,当使用浮点类型floatFloatdoubleDouble)时,小数类型会产生多余的错误数字。浮点技术特意放弃精度以获得执行速度。

BigDecimal

如果您必须使用分数,并且需要准确性,请使用BigDecimal类。

在本例中,假设您想要小时和分钟,同时舍去任何小数部分的分钟。因此,我对Duration调用了toMinutes方法。

BigDecimal minutesPerHour = new BigDecimal ( 60L ); // Use var/constant for clarity of your intent.
BigDecimal minutes = new BigDecimal ( d.toMinutes () );
BigDecimal fractionalHours = minutes.divide ( minutesPerHour );

frationalHours.toString(): 8.5

您可以在IdeOne.com上查看此示例代码。

如果您坚持使用这些小数而不是Duration对象和ISO 8601文本,则可能需要使用BigDecimal功能进行舍入。


关于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等等。


2
今日免费次数已满, 请开通会员/明日再来
    String[] a = "08:30:00".split(":");
    double d = Integer.parseInt(a[0]) + Integer.parseInt(a[1]) / 60.0;

是的,这正是我正在寻找的。在这种情况下,我必须使用d = d + Integer.parseInt(a[0]) + Integer.parseInt(a[1])/60.0 + Integer.parseInt(a[2])/3600.0;来整合秒值,但你让我走上了正确的轨道。谢谢! - Kael Eppcohen

0
我会使用 String.split() 来完成这个任务。它会根据你在参数中指定的正则表达式/分隔符将其拆分为数组。就像这样,
String time = "08:30:00";
String[] splitValues = time.split(":");
double hour = splitValue[0];
double minute = splitValue[1];
double seconds = splitValue[2];

然后您可以将这些值相加。您知道一小时有60分钟,一分钟有60秒。您可以通过分别除以60和3600将它们转换为小时。然后,只需要简单地进行加法运算即可。


不是正则表达式本身,但是split方法使用正则表达式来分割字符串。我会修改答案。 - Cache Staheli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接