【问题标题】:How can I find the amount of seconds passed from the midnight with Java?如何使用 Java 找到从午夜经过的秒数?
【发布时间】:2010-12-08 16:00:05
【问题描述】:

我需要一个函数来告诉我从午夜过去了多少秒。我目前正在使用System.currentTimeMillis(),但它给了我类似 UNIX 的时间戳。

如果我也能得到毫秒,那对我来说将是一个奖励。

【问题讨论】:

  • 哪个时区?当前的默认时区、UTC 或其他时区?

标签: java time


【解决方案1】:

如果您使用 Java >= 8,这很容易做到:

ZonedDateTime nowZoned = ZonedDateTime.now();
Instant midnight = nowZoned.toLocalDate().atStartOfDay(nowZoned.getZone()).toInstant();
Duration duration = Duration.between(midnight, Instant.now());
long seconds = duration.getSeconds();

如果您使用的是 Java 7 或更低版本,则必须通过日历获取从午夜开始的日期,然后进行减法。

Calendar c = Calendar.getInstance();
long now = c.getTimeInMillis();
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
long passed = now - c.getTimeInMillis();
long secondsPassed = passed / 1000;

【讨论】:

  • 很好的答案,第一个更适合我。谢谢。
  • 如果有一个 API 需要是不可变的并与 Builder 对象组装在一起,那将是 Java SE 日历/日期 API。我无法想象他们在想什么。
  • 仅供参考,Calendar 和 Joda-Time 现在都已过时。 (a) 麻烦的旧日期时间类,例如 java.util.Calendar 现在是 legacy,被 java.time 类取代。 (b) Joda-Time 项目现在位于 maintenance mode,团队建议迁移到 java.time 类。
  • 如果使用 Java 6 或 Java 7,他们应该使用 ThreeTen-Backport 项目来访问大部分 java.time 功能。永远不要使用Calendar/Date。没必要,那些遗留类是一团糟。
  • java.time.ZonedDateTime 没有atStartOfDay() 如您的回答所暗示的方法。 java.time.LocalDate 有。
【解决方案2】:

java.time

使用 Java 8 及更高版本中内置的 java.time 框架。见Tutorial

import java.time.LocalTime
import java.time.ZoneId

LocalTime now = LocalTime.now(ZoneId.systemDefault()) // LocalTime = 14:42:43.062
now.toSecondOfDay() // Int = 52963

最好明确指定ZoneId,即使您需要默认值。

【讨论】:

  • 这种方法并不具体。 LocalTime通常表示一天中的时间。这个类只知道一般的 24 小时工作日。由于缺乏特定时区的详细信息,此类无法了解有关夏令时 (DST) 等异常情况的任何信息。例如,在美国,夏令时意味着一天可以是 23、24 或 25 小时。因此,在美国,直到午夜的时间跨度从一天到另一天可能相差 ± 1 小时。
【解决方案3】:

tl;博士

“午夜”是一个模糊的术语,最好不要说。专注于一天的第一刻。

捕捉特定地区(时区)人们使用的挂钟时间中看到的当前时刻。

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

通过调用ZonedDateTime::get 并传递ChronoField 枚举对象,计算从一天的第一刻开始经过的时间。

整个seconds

int secondOfDay = zdt.get( ChronoField.SECOND_OF_DAY ) ;

Milliseconds.

int milliOfDay = zdt.get( ChronoField.MILLI_OF_DAY ) ;

Microseconds.

int microOfDay = zdt.get( ChronoField.MICRO_OF_DAY ) ;

Nanoseconds.

int nanoOfDay = zdt.get( ChronoField.NANO_OF_DAY ) ;

确定一天中的第一刻。

请注意,一天并不总是从 00:00:00 开始。某些时区中的某些日期可能从一天中的另一个时间开始,例如 01:00:00。始终让 java.time 使用 atStartOfDay 方法确定一天中的第一刻。

Instant then =                             // Represent a moment in UTC.
    ZonedDateTime                          // Represent a moment as seen through the wall-clock time used by the people of a particular region (a time zone).
    .now(                                  // Capture the current moment. Holds up to nanosecond resolution, but current hardware computer clocks limited to microseconds for telling current time.
        ZoneId.of( "Africa/Casablanca" )   // Specify the time zone. Never use 2-4 letter pseudo-zones such as `IST`, `PST`, `EST`.
    )                                      // Returns a `ZonedDateTime` object.
    .toLocalDate()                         // Extract the date-only portion, without time-of-day and without time zone.
    .atStartOfDay(                         // Deterimine the first moment of the day on that date in that time zone. Beware: The day does *not* always begin at 00:00:00.
        ZoneId.of( "Africa/Casablanca" )   // Specify the time zone for which we want the first moment of the day on that date.
    )                                      // Returns a `ZonedDateTime` object.
    .toInstant()                           // Adjusts from that time zone to UTC. Same moment, same point on the timeline, different wall-clock time.
;

将经过的时间表示为Duration,这是一个与时间线无关的时间跨度。

Duration                                   // Represent a span-of-time unattached to the timeline in terms of hours-minutes-seconds.
.between(                                  // Specify start and stop moments.
    then ,                                 // Calculated in code seen above.
    Instant.now()                          // Capture current moment in UTC. 
)                                          // Returns a `Duration` object.
.getSeconds()                              // Extract the total number of whole seconds accross this entire span-of-time.

java.time

Java 8 及更高版本已嵌入 java.time 框架。

通过使用ZonedDateTime 和时区,我们正在处理Daylight Saving Time (DST) 等异常情况。例如,在美国一天可以是 23、24 或 25 小时。因此,到明天的时间可能会因一天而异,相差 ±1 小时。

首先获取当前时刻。

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

现在提取仅日期部分,LocalDate,并使用该日期询问 java.time 当天开始的时间以获取我们所需的时区。不要假设一天从 00:00:00 开始。夏令时 (DST) 等异常意味着一天可能从另一个时间开始,例如 01:00:00。

ZonedDateTime todayStart = now.toLocalDate().atStartOfDay( z );  // Crucial to specify our desired time zone!

现在我们可以得到当前时刻和今天开始之间的增量。这种与时间线无关的时间跨度由Duration 类表示。

Duration duration = Duration.between( todayStart , now );

Duration 对象询问整个时间跨度内的总秒数。

long secondsSoFarToday = duration.getSeconds();

关于java.time

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

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

    【解决方案4】:

    获取当前时区自午夜以来秒数的最简单、最快的方法:

    一次性设置:

    static final long utcOffset = TimeZone.getDefault().getOffset(System.currentTimeMillis());
    

    如果你使用 Apache Commons,你可以使用 DateUtils.DAY_IN_MILLIS,否则定义:

    static final long DAY_IN_MILLIS = 24 * 60 * 60 * 1000;
    

    然后,只要你需要时间......:

    int seconds = (int)((System.currentTimeMillis() + utcOffset) % DateUtils.DAY_IN_MILLIS / 1000);
    

    请注意,如果您的程序有可能运行足够长的时间,并且夏令时发生更改...

    【讨论】:

    • 您可以使用DateUtils.DAY_IN_MILLIS 常量而不是计算它。
    • @BillMote,DateUtils 仅在您使用 Apache Commons 时可用。将其作为选项进行了编辑...
    • 好点。没有考虑到这一点,但我确实喜欢可读性。
    • 这实际上是最好的答案,因为它是最高效的
    【解决方案5】:

    使用 JodaTime 你可以调用:

    int seconds = DateTime.now().secondOfDay().get();
    int millis = DateTime.now().millisOfDay().get();
    

    【讨论】:

    【解决方案6】:

    如果您收到有关日历受到保护的错误,请使用 getTime().getTime() 而不是 getTimeInMillis()。记住你的导入:

    import java.util.*; 
    

    将在您调试时将它们全部包含在内:

        Calendar now = Calendar.getInstance();
        Calendar midnight = Calendar.getInstance();
        midnight.set(Calendar.HOUR_OF_DAY, 0);
        midnight.set(Calendar.MINUTE, 0);
        midnight.set(Calendar.SECOND, 0);
        midnight.set(Calendar.MILLISECOND, 0);
        long ms = now.getTime().getTime() - midnight.getTime().getTime();
        totalMinutesSinceMidnight = (int) (ms / 1000 / 60);
    

    【讨论】:

      【解决方案7】:
      (System.currentTimeMillis()/1000) % (24 * 60 * 60)
      

      【讨论】:

      • 这将为您提供自 UTC 最后一天开始以来的秒数,而不是本地时区。
      • 当然它适用于 DST 转换。发生 DST 转换时,自午夜以来经过的秒数不会改变;只有当地时间改变。
      【解决方案8】:

      和@secmask 一样,如果您需要距离格林威治标准时间午夜的毫秒数,请尝试

      long millisSinceGMTMidnight = System.currentTimeMillis() % (24*60*60*1000);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-06-09
        • 1970-01-01
        • 1970-01-01
        • 2012-10-03
        • 2012-08-12
        • 2012-12-31
        • 1970-01-01
        相关资源
        最近更新 更多