【问题标题】:How to get the total number of minutes in the day so far?到目前为止,如何获得一天中的总分钟数?
【发布时间】:2014-11-02 09:21:39
【问题描述】:

到目前为止,您如何在 Java (Android) 中获得一天中的总分钟数?这可能吗? 例如,如果它是上午 12:37,我希望它返回 int 37(当天到目前为止 37 分钟)。或者,如果是凌晨 1:41,我希望它返回 int 101(当天到目前为止 101 分钟),或者如果是下午 12:20,它会返回 int 740(当天总共 740 分钟)。

【问题讨论】:

  • 我会使用 Calendar.get 的结果对代表现在的时间的各种(小时、分钟、秒)字段进行数学运算。还可以计算现在和“今天的开始”之间的差异,因为肯定存在重复的问题。
  • 您在这样做时遇到了什么问题?如果你能得到当前时间,那么我猜你需要做的只是一个简单的数学运算
  • @TheQuickBrownFox,哇,我不敢相信我从来没有想过。
  • @Jonjongot 不,你不能只使用简单的数学。夏令时意味着天可以是 23、24 或 25 小时。例如,03:00 可以是 120 或 180 分钟。除了 DST,您还需要考虑各个地方的其他异常情况。而且您需要时区才能知道一天的开始时间(例如:巴黎 vs 蒙特利尔)。为此类工作使用好的日期时间库。在 Android 中,这意味着 Joda-Time。见my answer

标签: java android date datetime android-calendar


【解决方案1】:

tl;博士

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
long minutesIntoTheDay = ChronoUnit.MINUTES.between( 
    zdt.toLocalDate().atStartOfDay( z ) ,
    zdt 
);

时区

其他答案不正确,因为它们没有考虑时区。如果你想要从一天开始的分钟数,哪一天?从加尔各答、巴黎或蒙特利尔开始的一天? 23 小时、24 小时、25 小时或其他长度的一天?

指定proper time zone name。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

使用 java.time

通过指定ZoneId,获取所需/预期时区的当前时刻ZonedDateTime

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

要获取一天中的分钟数,请获取当天的第一个时刻,然后计算经过的时间。

ZonedDateTime startOfDay = now.toLocalDate().atStartOfDay( z );

DurationChronoUnit 枚举的形式计算经过的时间。

Duration duration = Duration.between( startOfDay , now );
long minutesIntoTheDay = duration.toMinutes();

……或者……

long minutesIntoTheDay = ChronoUnit.MINUTES.between( startOfDay , now );

示例:Europe/Amsterdam

以下示例显示了 2017 年 3 月 26 日凌晨 2 点在时区 Europe/Amsterdam 中的 DST 转换(“Spring forward”)for the Netherlands

LocalDate march26 = LocalDate.of ( 2017, Month.MARCH, 26 );
LocalTime twoAm = LocalTime.of ( 2, 0 );
ZoneId z = ZoneId.of ( "Europe/Amsterdam" );
ZonedDateTime start = march26.atStartOfDay ( z );
ZonedDateTime stop = ZonedDateTime.of ( march26, twoAm, z );
long minutes = ChronoUnit.MINUTES.between ( start, stop );
Duration duration = Duration.between ( start, stop );
long durationAsMinutes = duration.toMinutes ( );
int minuteOfDay = stop.get ( ChronoField.MINUTE_OF_DAY );

转储到控制台。

System.out.println ( "start: " + start );
System.out.println ( "stop: " + stop );
System.out.println ( "minutes: " + minutes );
System.out.println ( "FYI: 4 * 60 = " + ( 4 * 60 ) + " | 3 * 60 = " + ( 3 * 60 ) + " | 2 * 60 = " + ( 2 * 60 ) );
System.out.println ( "duration.toString(): " + duration + " | durationAsMinutes: " + durationAsMinutes );
System.out.println ( "minuteOfDay: " + minuteOfDay );

你可以看到这个code run live at IdeOne.com

开始:2017-03-26T00:00+01:00[欧洲/阿姆斯特丹]

停止:2017-03-26T03:00+02:00[欧洲/阿姆斯特丹]

分钟:120

仅供参考:4 * 60 = 240 | 3 * 60 = 180 | 2 * 60 = 120

duration.toString(): PT2H |持续时间:120

minuteOfDay: 180

输出中的注释:

  • offset-from-UTC 变化一个小时,从 +01:00 变为 +02:00
  • 我们请求的时间是凌晨 2 点,但该日期没有这样的时间。由于时钟提前了一个小时,所以在那个日期根本不存在凌晨两点。当然,时空没有弯曲也没有扭曲。从午夜到凌晨 3 点,实际时间只有 两个 小时,而不是三个。 java.time 类的设计者选择通过将时间值提前调整为有效时间来解决问题。阅读文档以确保您理解并同意此类行为。
  • ChronoField.MINUTE_OF_DAY 的结果不正确/不精确,因为该功能仅考虑一般的 24 小时天数,而不是实际的异常日期,例如具有 DST 转换的日期。我们看到 180 分钟,而实际只过去了 120 分钟。

更正:此答案以前建议使用ChronoField.MINUTE_OF_DAY。这是一个糟糕的建议,因为该功能使用通用的 24 小时工作日。夏令时 (DST) 等异常情况将被忽略。因此,对于某些时区的特定日期,结果可能不准确/正确。这种行为有明确的记录:

ChronoField MINUTE_OF_DAY

公共静态最终 ChronoField MINUTE_OF_DAY

一天中的每一分钟。

这计算一天中的分钟,从 0 到 (24 * 60) - 1。此字段对于所有日历系统具有相同的含义。

解析此字段时,它的行为等同于以下内容:该值在严格和智能模式下验证,但在宽松模式下不验证。该值被拆分为 MINUTE_OF_HOUR 和 HOUR_OF_DAY 字段。


关于java.time

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

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

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

从哪里获得 java.time 类?

【讨论】:

  • 夏令时开始的那一天(欧洲/阿姆斯特丹的 fi 2017/03/26 12:00),MINUTE_OF_DAY 报告 720 (12*60),但我们刚刚跳过了 60 分钟1:59 至 3:00。所以应该是 660。JodaTime 也是这样。另一方面,dstStartDayAtStartOfDay.until(dstStartDayAtNoon,ChronoUnit.MINUTES) 报告正确的 660 分钟(以及HOURS 11h)。当 DST 结束时,模式重复:.until() 从午夜到 2017 年 10 月 29 日的午餐时间提供 13 小时/780 分钟。到目前为止,我找不到两个结果之间差异的解释。
  • @Ivin 你是对的,我建议使用ChronoField.MINUTE_OF_DAY 是不明智的。该功能仅适用于一般的 24 小时工作日,不适用于 DST 转换等异常日期。我修改了此答案以建议其他功能。
【解决方案2】:

我实际上使用了Calendar 类来解决这个问题。

这是代码,currentMinuteOfDay 是总分钟数。

Calendar now = Calendar.getInstance();
        int hour = now.get(Calendar.HOUR_OF_DAY);
        int minute = now.get(Calendar.MINUTE);

        int currentMinuteOfDay = ((hour * 60) + minute);

【讨论】:

    【解决方案3】:

    基于Get current time and date on Android 帖子的答案:

    public int getTodayMinutesAsOfNow() {
        Calendar c = Calendar.getInstance(); 
        return c.get(Calendar.HOUR_OF_DAY)*60 + c.get(Calendar.MINUTE);
    }
    

    【讨论】:

      【解决方案4】:

      将您的开始时间设置为午夜。然后,当您想要已经过去的总分钟数时,只需获取当前时间。然后获取两次的整数,从currentTime_hour 中减去startTime_hour

      然后从currentTime 分钟中获取时间的分钟部分。使用此关系将分钟转换为十进制:

      30mins/.50
      

      这很简单,30 分钟 = 0.50。在代码中它看起来像这样:

      currentTime_mins_decimal = .50 * currentTime_mins / 30;
      

      现在您要将第一次减法的结果与currentTime_mins_decimal 相加,然后将整个结果乘以 60。

      然后使用相同的关系将十进制转换为分钟:30mins/.50 更改的好处是,如果您的开始时间不是午夜而是带有分钟的时间,比如说 12:55,当您进行算术运算时,您不会得到准确的结果。

      【讨论】:

      • 你如何得到“总分钟数”?走那条路然后改变没有任何好处。
      【解决方案5】:

      我很傻,

      这是伪算法:

        1. Get the current time in hours and minutes
        2. Multiple hours * 60 + minutes, and this is your answer!
      

      我建议使用 Date 类:

       Date date = new Date();
      

      您可以阅读更多关于Datehere 的信息。

      如果您有任何问题,请告诉我!

      【讨论】:

      • AM/PM 是人工指示符;所有日历/日期对象都使用 24 小时制(但请注意奇怪的访问,例如 HOUR 与 HOUR_OF_DAY)。
      • 啊,我明白了;我没有意识到这一点。感谢您的新知识和澄清@user2864740! :0)
      • 此答案忽略时区。 java.util.Date 类没有时区,仅代表 UTC。如果你想要从一天开始的分钟数,你必须做其他事情。这一天在加尔各答、巴黎和蒙特利尔的不同时间开始。
      猜你喜欢
      • 1970-01-01
      • 2018-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-22
      相关资源
      最近更新 更多