如何从当前时间获取当前毫秒数

130
注意,我不想要自纪元以来的毫秒数。我想要当前时钟上的毫秒数。
所以举个例子,我有这段代码。
Date date2 = new Date(); 
Long time2 = (long) (((((date2.getHours() * 60) + date2.getMinutes())* 60 ) + date2.getSeconds()) * 1000);

有没有一种方法可以获得日期的毫秒数? 还有其他的方法吗?
注意:System.currentTimeMillis() 给我提供了自纪元以来的毫秒数,这不是我要找的东西。

2
你的意思是“一秒钟内的毫秒数”,因此该值始终在区间[0, 999]中,对吗?@thinksteep请阅读最后一句话。 - Matt Ball
@Lemonio 给出一个例子会让你的问题更清晰。 - Basil Bourque
FYI,旧的日期时间类(如java.util.Date)现在已成为遗留系统,被Java.time类替代。 - Basil Bourque
FYI,诸如java.util.Date之类的老旧日期时间类现在已经成为遗留系统,被Java.time类所取代。请参阅Oracle教程 - Basil Bourque
@Basil Bourque 源代码是什么? - Chris Neve
1
@ChrisNeve JEP 150 已获得 Brian Goetz 的认可,JSR 310 被一致通过,Oracle 发布了一篇 技术文章,并用新的 java.time 教程 替换了旧的日期时间 Oracle 教程。 - Basil Bourque
11个回答

203

你的意思是什么?

long millis = System.currentTimeMillis() % 1000;

顺便提一句,Windows不允许时间旅行到1969年。

C:\> date
Enter the new date: (dd-mm-yy) 2/8/1969
The system cannot accept the date entered.

9
请注意,如果您将时间旅行到 Unix 纪元之前,这将会给出一个负值,而使用 c.get(Calendar.MILLISECOND) 则不应该出现这种情况。始终考虑边界情况! - Jon Skeet
39
Java 不支持时间旅行。 - R. Martinho Fernandes
1
@MarkusMikkolainen:不是的,System.currentTimeMillis() 不受时区影响。 - Jon Skeet
是的,这就是为什么如果有人创建了一个不在秒边界上的时区,那么%1000的计算将会出错。如果一个时区从.001开始,那么%1000的计算将会偏移1毫秒。 - Markus Mikkolainen
1
@PeterLawrey:这可能是这样,也可能不是。这取决于实现方式。从Date的文档中可以看到:“一秒钟由0到61之间的整数表示;值为60和61仅在闰秒时出现,即使在Java实现中正确跟踪闰秒的情况下也是如此。由于目前引入闰秒的方式,极不可能在同一分钟内发生两个闰秒,但本规范遵循ISO C的日期和时间约定。” - Jon Skeet
显示剩余7条评论

26

使用日历(Calendar)

Calendar.getInstance().get(Calendar.MILLISECOND);
或者
Calendar c=Calendar.getInstance();
c.setTime(new Date()); /* whatever*/
//c.setTimeZone(...); if necessary
c.get(Calendar.MILLISECOND);

实际上,我认为它几乎总是等于System.currentTimeMillis()%1000;,除非有人使用了闰秒或某个日历的纪元不在秒边界上。


日历默认已经是当前时间,并且毫秒不需要加s。 - kgautron

17
Calendar.getInstance().get(Calendar.MILLISECOND);

15

简而言之

您需要将当前时间的一小部分表示为毫秒数(不是从纪元开始计算)。

Instant.now()                               // Get current moment in UTC, then…
       .get( ChronoField.MILLI_OF_SECOND )  // interrogate a `TemporalField`.

2017-04-25T03:01:14.113Z → 113

  1. 获取以纳秒(十亿分之一秒)为单位的小数部分。
  2. 除以一千以截取毫秒(千分之一秒)。

请参见IdeOne.com上的代码实时运行

使用java.time

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

在UTC中捕获当前时刻。

Instant.now()

使用Instant.get方法来查询TemporalField的值。在我们的案例中,我们需要的TemporalFieldChronoField.MILLI_OF_SECOND
int millis = Instant.now().get( ChronoField.MILLI_OF_SECOND ) ;  // Get current moment in UTC, then interrogate a `TemporalField`.

或者自己做数学计算。

更可能是您针对特定的时区提出此问题。毫秒的分数可能与Instant相同,但由于时区存在许多异常情况,我不敢做出这样的假设。

ZonedDateTime zdt = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) ) ;

查询小数秒。问题要求毫秒,但是java.time类使用更精细的纳秒分辨率。这意味着纳秒数将从0到999,999,999范围内变化。

long nanosFractionOfSecond = zdt.getNano();

如果你真的需要毫秒,可以通过将更精细的数据除以一百万来截断它。例如,半秒钟是500,000,000纳秒,也等于500毫秒。
long millis = ( nanosFractionOfSecond / 1_000_000L ) ;  // Truncate nanoseconds to milliseconds, by a factor of one million.

关于 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更多。请注意,保留 HTML 标签。

14

我尝试了几个,但它们似乎会在1000处重置。

这一个绝对有效,并且应该考虑到年份。

long millisStart = Calendar.getInstance().getTimeInMillis();

如果需要的话,同样的方式处理结束时间。


1
回答了错误的问题。这是自纪元以来的当前毫秒数,而不是当前时间的毫秒部分。 - Sean Van Gorder
不,我确认System和Calendar返回的数字完全相同:1627732708315:1627732708315 - AKTanara

5
  1. long timeNow = System.currentTimeMillis();
  2. System.out.println(new Date(timeNow));

2014年4月4日 星期五 下午2:27:05


3

Joda-Time

我认为你可以使用Joda-Time完成这个任务。看一下DateTime类及其getMillisOfSecond方法。例如:

int ms = new DateTime().getMillisOfSecond() ;

编译错误:“getMillis() 受保护访问权限”;需要使用 get()。同时请注意,new DateTime(new Date()) 等同于简单地编写 new DateTime() - Jonik
方法 millisOfSecond 访问一个对象,随后调用 get 从该对象中提取一个基本类型的 int。您可以使用方便的 getter 方法 getMillisOfSecond 来折叠这两个调用。Joda-Time 在其许多属性中遵循此模式。 - Basil Bourque
1
FYI,Joda-Time 项目现已进入 维护模式,团队建议迁移至 java.time 类。 - Basil Bourque

1

我使用Java 8进行了测试。无论顺序如何,构建器始终需要0毫秒,并在1000次连接迭代下将26和33之间的连接时间为毫秒。

希望这能帮到你,可以尝试在你的IDE中测试。

public void count() {

        String result = "";

        StringBuilder builder = new StringBuilder();

        long millis1 = System.currentTimeMillis(),
            millis2;

        for (int i = 0; i < 1000; i++) {
            builder.append("hello world this is the concat vs builder test enjoy");
        }

        millis2 = System.currentTimeMillis();

        System.out.println("Diff: " + (millis2 - millis1));

        millis1 = System.currentTimeMillis();

        for (int i = 0; i < 1000; i++) {
            result += "hello world this is the concat vs builder test enjoy";
        }

        millis2 = System.currentTimeMillis();

        System.out.println("Diff: " + (millis2 - millis1));
    }

0
在Java 8中,您可以简单地执行以下操作:
ZonedDateTime.now().toInstant().toEpochMilli()

返回:自1970-01-01T00: 00: 00Z纪元以来的毫秒数

1
[A] 这不是问题要求的内容。明确表示他们不想要自纪元参考日期以来的毫秒计数。 [B] 您可以通过删除ZonedDateTime来缩短它:Instant.now().toEpochMilli() - Basil Bourque

0
您可以使用java.util.Calendar类获取毫秒级时间。 例如:
Calendar cal = Calendar.getInstance();
int milliSec = cal.get(Calendar.MILLISECOND);
// print milliSec

java.util.Date date = cal.getTime();
System.out.println("Output: " +  new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss:SSS").format(date));

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