在午夜之前获得毫秒



我正在创建一个Android小部件,我想每天晚上午夜更新。我正在使用AlarmManager,我需要找出从当前时间到午夜还剩多少毫秒。这是我的代码:

AlarmManager mAlarmManager = (AlarmManager)context.getSystemService(android.content.Context.ALARM_SERVICE);
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, millisecondsUntilMidnight, mSrvcPendingingIntent);

如何计算距离午夜还剩多少毫秒?

提前谢谢你。

使用日历来计算它:

        Calendar c = Calendar.getInstance();
        c.add(Calendar.DAY_OF_MONTH, 1);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        long howMany = (c.getTimeInMillis()-System.currentTimeMillis());

tl;dr

java.time.Duration
.between( now , tomorrowStart )
.toMillis()

java.time

Java 8 及更高版本内置了 java.time 框架。这些新类取代了旧的日期时间类(java.util.Date/.日历)与 Java 捆绑在一起。也取代了由同一个人开发的Joda-Time。许多java.time功能被向后移植到Java 6和7,并进一步适应Android(见下文)。

时区对于确定日期至关重要。对于任何给定时刻,日期因区域而异。例如,法国巴黎午夜过后几分钟是新的一天,而在魁北克蒙特利尔仍然是"昨天"。

continent/region 的格式指定正确的时区名称,例如 America/MontrealAfrica/CasablancaPacific/Auckland 。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!

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

我们希望获得运行到(但不包括)第二天第一个时刻的毫秒数。

我们必须通过LocalDate课才能在一天的第一刻获得。所以在这里我们从一个ZonedDateTime开始 得到一个 LocalDate ,然后得到另一个ZonedDateTime .关键是在LocalDate上调用atStartOfDay

LocalDate tomorrow = now.toLocalDate().plusDays(1);
ZonedDateTime tomorrowStart = tomorrow.atStartOfDay( z );

请注意,我们不会对一天中的时间进行硬编码 00:00:00。由于夏令时 (DST) 等异常情况,一天可能会从另一个时间(如 01:00:00)开始。让java.time决定第一个时刻。

现在我们可以计算经过的时间了。在java.time中,我们使用Duration类。 java.time框架具有更精细的纳秒分辨率,而不是java.util.Date和Joda-Time使用的更粗糙的毫秒。但Duration包括一个方便的getMillis方法,正如问题所要求的那样。

Duration duration = Duration.between( now , tomorrowStart );
long millisecondsUntilTomorrow = duration.toMillis();

查看此代码在 IdeOne.com 实时运行。

now.toString(): 2017-05-02T12:13:59.379-04:00[美国/蒙特利尔]

明天开始字符串(): 2017-05-03T00:00-04:00[美国/蒙特利尔]

毫秒直到明天:42360621

<小时 />

关于 java.time

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

Joda-Time 项目现在处于维护模式,建议迁移到 java.time 类。

要了解更多信息,请参阅 Oracle 教程。并搜索堆栈溢出以获取许多示例和解释。规范为 JSR 310。

您可以直接与数据库交换java.time对象。使用符合 JDBC 4.2 或更高版本的 JDBC 驱动程序。不需要字符串,不需要java.sql.*类。

从哪里获得java.time类?

    Java SE 8、Java SE
  • 9、Java SE 10 及更高版本
  • 内置。
  • 具有捆绑实现的标准 Java API 的一部分。
  • Java 9添加了一些小功能和修复。
  • Java SE
  • 6Java SE 7
  • 许多java.time功能在ThreeTen-Backport中向后移植到Java 6和7。
  • 人造人
  • java.time 类的 Android 捆绑包实现的更高版本。
  • 对于早期的Android(<26),ThreeTenABP项目适应了ThreeTen-Backport(如上所述)。请参阅如何使用ThreeTenABP...
<小时 />

乔达时间

更新:Joda-Time项目现在处于维护模式,团队建议迁移到java.time类。为了历史起见,我保留了本节,但建议使用java.time和ThreeTenABP,如上所述。

在Android中,你应该使用Joda-Time库,而不是臭名昭著的Java.util.Date/。日历类。

Joda-Time 提供一天中的毫秒命令。但我们在这里并不需要它。

相反,我们只需要一个Duration对象来表示直到第二天第一个时刻的时间跨度。

时区对于确定"明天"何时开始至关重要。通常,最好指定而不是隐式依赖 JVM 的当前默认时区,该时区可能随时更改。或者,如果你真的想要 JVM 的默认值,请通过调用 DateTimeZone.getDefault 来显式请求它,以使你的代码自我记录。

可能是两行

DateTime now = DateTime.now( DateTimeZone.forID( "America/Montreal" ) );
long milliSecondsUntilTomorrow = new Duration( now , now.plusDays( 1 ).withTimeAtStartOfDay() ).getMillis();

让我们把它拆开。

DateTimeZone zone = DateTimeZone.forID( "America/Montreal" ); // Or, DateTimeZone.getDefault()
DateTime now = DateTime.now( zone );
DateTime tomorrow = now.plusDays( 1 ).withTimeAtStartOfDay();  // FYI the day does not *always* start at 00:00:00.0 time.
Duration untilTomorrow = new Duration( now , tomorrow );
long millisecondsUntilTomorrow = untilTomorrow.getMillis();

转储到控制台。

System.out.println( "From now : " + now + " until tomorrow : " + tomorrow + " is " + millisecondsUntilTomorrow + " ms." );

运行时。

从现在开始:2015-09-20T19:45:

43.432-04:00到明天:2015-09-21T00:00:00.000-04:00是15256568毫秒。

尝试以下操作:

Calendar c = Calendar.getInstance();
long now = c.getTimeInMillis();
c.add(Calendar.DATE, 1);
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
long millisecondsUntilMidnight = c.getTimeInMillis() - now;
AlarmManager mAlarmManager = (AlarmManager)context.getSystemService(android.content.Context.ALARM_SERVICE);
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, millisecondsUntilMidnight, mSrvcPendingingIntent);

这行得通吗?

long MILLIS_IN_DAY = 86400000;
long currentTime = System.currentTimeInMillis();
long millisTillNow = currentTime % MILLIS_IN_DAY;
long millisecondsUntilMidnight = MILLIS_IN_DAY - millisTillNow;
您可以使用

AlarmManager.RTC而不是AlarmManager.ELAPSED_REALTIME,只需将日历设置为您想要的时间:

// Create a calendar for midnight
Calendar todayMidnight = Calendar.getInstance();
todayMidnight.add(Calendar.DATE, 1);
todayMidnight.set(Calendar.HOUR_OF_DAY, 0);
todayMidnight.set(Calendar.MINUTE, 0);
todayMidnight.set(Calendar.SECOND, 0);
// Create an alarm going off at midnight
mAlarmManager.set(
   AlarmManager.RTC, 
   todayMidnight.getTimeInMillis(), 
   mSrvcPendingingIntent
);

使用以下方式,无需担心设置DAY_OF_MONTH。

    long msInDay = 86400000;
    Calendar c = Calendar.getInstance();
    c.set(Calendar.HOUR_OF_DAY, 0);
    c.set(Calendar.MINUTE, 0);
    c.set(Calendar.SECOND, 0);
    c.set(Calendar.MILLISECOND, 0);
    System.out.print(msInDay - (System.currentTimeMillis() - c.getTimeInMillis()));

最新更新