如何将 HH:mm:ss.SSS 转换为毫秒?
Posted
技术标签:
【中文标题】如何将 HH:mm:ss.SSS 转换为毫秒?【英文标题】:How to convert HH:mm:ss.SSS to milliseconds? 【发布时间】:2012-02-08 05:19:45 【问题描述】:我有一个字符串00:01:30.500
,它相当于90500
毫秒。我尝试使用SimpleDateFormat
,它给出包括当前日期在内的毫秒数。我只需要毫秒级的字符串表示。我是否必须编写自定义方法,它将拆分和计算毫秒?或者有没有其他方法可以做到这一点?谢谢。
我试过如下:
String startAfter = "00:01:30.555";
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
Date date = dateFormat.parse(startAfter);
System.out.println(date.getTime());
【问题讨论】:
我认为00:01:30.500
表示持续时间,时间量,1 分 30.5 秒。如果是这样,Date
和 SimpleDateFormat
是使用错误的类。持续时间不是日期。另外我建议你永远不要使用这些类。它们设计不佳且过时,尤其是后者出了名的麻烦。使用java.time, the modern Java date and time API。
【参考方案1】:
您可以使用SimpleDateFormat
来执行此操作。你只需要知道两件事。
-
所有日期都在内部以 UTC 表示
.getTime()
返回自 1970-01-01 00:00:00 UTC 以来的毫秒数。
package se.wederbrand.milliseconds;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class Main
public static void main(String[] args) throws Exception
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String inputString = "00:01:30.500";
Date date = sdf.parse("1970-01-01 " + inputString);
System.out.println("in milliseconds: " + date.getTime());
【讨论】:
无需在前面加上 yyyy-MM-dd 和 1970-01-01。如果时区设置为 GMT,则按照 OP 的方式进行解析。 @JBNizet 是真的,而且是一个好点。我特意包含了额外的日期信息,因为我认为它可以更好地显示真实情况。 @AndreasWederbrand:让它在这里工作的“诀窍”是将日期设置为 1970 年 1 月 1 日。但是假设我不给这一天,那么它会工作吗? @bks,如果你不设置 1970-01-01,你会在这个问题上得到太多的毫秒数。【参考方案2】:如果您想自己解析格式,可以使用正则表达式轻松完成,例如
private static Pattern pattern = Pattern.compile("(\\d2):(\\d2):(\\d2).(\\d3)");
public static long dateParseRegExp(String period)
Matcher matcher = pattern.matcher(period);
if (matcher.matches())
return Long.parseLong(matcher.group(1)) * 3600000L
+ Long.parseLong(matcher.group(2)) * 60000
+ Long.parseLong(matcher.group(3)) * 1000
+ Long.parseLong(matcher.group(4));
else
throw new IllegalArgumentException("Invalid format " + period);
但是,这种解析非常宽松,可以接受 99:99:99.999 并让值溢出。这可能是缺点或功能。
【讨论】:
嘿,我使用了你的方法,但它给出的结果之间添加了 - 字符,这是因为你使用了 3600000 的 L 可能不会,L 是为了让它变长。哪个部分给出了带有 - 的结果? dateParseRegExp 返回一个没有 - 的 long(除非它是负数)。它是具有 - 的匹配组之一吗? 糟糕,不是因为我的坏。"(\\d2):(\\d2):(\\d2).(\\d[0-9])"
如果最后一个数字是 2 位数,这不会失败
@Mehran 但它会给出错误的数字答案。你想达到什么目的?如果您需要可变小数位数的解决方案,请作为新问题发布。【参考方案3】:
使用JODA:
PeriodFormatter periodFormat = new PeriodFormatterBuilder()
.minimumParsedDigits(2)
.appendHour() // 2 digits minimum
.appendSeparator(":")
.minimumParsedDigits(2)
.appendMinute() // 2 digits minimum
.appendSeparator(":")
.minimumParsedDigits(2)
.appendSecond()
.appendSeparator(".")
.appendMillis3Digit()
.toFormatter();
Period result = Period.parse(string, periodFormat);
return result.toStandardDuration().getMillis();
【讨论】:
【参考方案4】:如果你想使用SimpleDateFormat
,你可以写:
private final SimpleDateFormat sdf =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
private long parseTimeToMillis(final String time) throws ParseException
return sdf.parse("1970-01-01 " + time).getTime();
但是自定义方法会更有效。 SimpleDateFormat
,由于它所有的日历支持、时区支持、夏令时支持等等,速度非常慢。如果您确实需要其中一些功能,那么缓慢是值得的,但由于您不需要,因此可能不需要。 (这取决于您调用此方法的频率,以及您的应用程序是否关注效率。)
另外,SimpleDateFormat
是非线程安全的,这有时很痛苦。 (在不了解您的应用程序的情况下,我无法猜测这是否重要。)
就个人而言,我可能会编写一个自定义方法。
【讨论】:
无需在前面加上 yyyy-MM-dd 和 1970-01-01。如果时区设置为 GMT,则按照 OP 的方式进行解析。 @JBNizet:在我的系统上确实如此,但 OP 写道,他/她的方法给出了“包括当前日期在内的毫秒数”,所以我假设他/她的 JDK 实现SimpleDateFormat
一定不能打电话给calendar.clear()
。我在 Javadoc 中没有看到任何表明 SimpleDateFormat
必须默认为 1970-01-01 的内容。你知道这是否有保证吗?【参考方案5】:
我提出了两个选择:
-
Time4J,一个高级外部日期、时间和时间间隔库。
java.time,内置的现代 Java 日期和时间 API。
SimpleDateFormat
和 Date
是错误的类,因为 1 分钟 30.5 秒的持续时间不是一个日期,而且这些类早已没有任何合理用途。
时间4J
这是优雅的解决方案。我们首先声明一个格式化程序:
private static final Duration.Formatter<ClockUnit> DURATION_FORMAT
= Duration.formatter(ClockUnit.class, "hh:mm:ss.fff");
然后像这样解析并转换为毫秒:
String startAfter = "00:01:30.555";
Duration<ClockUnit> dur = DURATION_FORMAT.parse(startAfter);
long milliseconds = dur.with(ClockUnit.MILLIS.only())
.getPartialAmount(ClockUnit.MILLIS);
System.out.format("%d milliseconds%n", milliseconds);
输出是:
90555 毫秒
java.time
java.time.Duration
类只能解析 ISO 8601 格式。所以我首先将您的字符串转换为该格式。它类似于PT00H01M30.555S
(不需要前导零,但我为什么要费心删除它们?)
String startAfter = "00:01:30.555";
String iso = startAfter.replaceFirst(
"^(\\d2):(\\d2):(\\d2\\.\\d3)$", "PT$1H$2M$3S");
Duration dur = Duration.parse(iso);
long milliseconds = dur.toMillis();
System.out.format("%d milliseconds%n", milliseconds);
输出和之前一样:
90555 毫秒
与 Time4J 的另一个区别是,Java Duration
可以直接转换为毫秒,而无需先转换为仅毫秒的Duration
。
链接
Time4J - Advanced Date, Time, Zone and Interval Library for Java Oracle tutorial: Date Time 解释如何使用 java.time。【讨论】:
以上是关于如何将 HH:mm:ss.SSS 转换为毫秒?的主要内容,如果未能解决你的问题,请参考以下文章
如何在进行选择查询时将 YYYY-MM-DD HH:mm:ss 中的时间戳转换为 Hive 中的 YYYY-MM-DD HH:mm:ss.SSS?
SimpleDateFormat 中的yyyy-MM-dd HH:mm:ss.SSS说明
来自 Hive 的 Pyspark 数据中带有毫秒 'YYYY-MM-DD hh:mm:ss.SSS' 的日期