以下是我用来获取当天00小时(长格式)的代码。

我在android中运行以下代码。

该方法在大多数情况下会正确返回该值。但是有时它会返回System.currentTimeMillis()的值。

import java.text.SimpleDateFormat;
import java.util.Date;
public static final SimpleDateFormat SD_FORMAT_DAY_MONTH_YEAR = new SimpleDateFormat("dd/MM/yyyy");


public static long getLongForCurrent00hr() {
    Date date = new Date();
    String time = SD_FORMAT_DAY_MONTH_YEAR.format(date);

    long value;
    try {
        Date date2 = SD_FORMAT_DAY_MONTH_YEAR .parse(time);
        value = date2.getTime();
    } catch (ParseException e) {
        value = 0;
    }
    return value;
}


为什么返回System.currentTimeMillis()?
我该如何解决这个问题?

我对了解为什么更感兴趣。

当我今天在仔细阅读这段代码时,我通过放置Logs进行了检查:

大多数时候返回:1462386600000

和几次System.currentTimeMillis()类似1462430867302。

最佳答案

您的示例代码有效

构架时,我认为您的代码没有问题(有关批评,请阅读下文)。

这里几乎显示了您的确切代码。两项更改:


我将您的格式常量设为局部变量。 (只是为了简化此演示,可以复制粘贴一个代码块)
我添加了几个电话以获取Instant,即UTC中的当前时刻。与java.util.Date类似,但Instant::toString创建一个显示UTC的字符串,而不是混淆JVM的当前时区。因此,您可以更清楚地看到,您确实是在JVM当前默认时区的第一天。就我而言,运行此代码时,JVM的当前默认时区为America/Los_Angeles,当前为offset-from-UTC的夏令时(DST)为-07:00(比UTC晚七个小时)。


示例代码。

Date date1 = new Date ();
SimpleDateFormat SD_FORMAT_DAY_MONTH_YEAR = new SimpleDateFormat ( "dd/MM/yyyy" );
String time = SD_FORMAT_DAY_MONTH_YEAR.format ( date1 );

Date date2 = null;
long value;
try {
    date2 = SD_FORMAT_DAY_MONTH_YEAR.parse ( time );
    value = date2.getTime ();
} catch ( ParseException e ) {
    value = 0;
}
System.out.println ( "date1: " + date1 + " date2: " + date2 + " value: " + value + " | instant 1: " + date1.toInstant () + " | instant 2: " + date2.toInstant () );


运行时。


  date1:​​2016年5月5日星期四16:55:40 PDT 2016 date2:2016年5月5日星期日太平洋夏令时间00:00:00 PDT价值:1462431600000 |即时1:2016-05-05T23:55:40.907Z |瞬间2:2016-05-05T07:00:00Z


太努力了

您的问题令人困惑,但似乎您正在尝试捕捉当天的第一刻。您正在以错误的方式进行操作,并且工作过于努力。

时区

您的代码似乎正在与java.util.Date类一起使用。该课程代表UTC时间轴上的时刻。

但是您不会在UTC上度过第一时间。当您解析该仅日期的字符串以生成新的java.util.Date(日期加上日期值,尽管名称具有误导性)时,JVM的当前默认时区将被隐式应用。将时区无形地注入该过程非常令人困惑。

相反,您应该自觉考虑时区,并始终使时区成为您的编码(如下所示)。

java.time

事实证明,旧的java.util.Date / .Calendar类设计不良,令人困惑且麻烦。它们现在已成为旧版,被Java 8和更高版本中内置的java.time框架所取代。 java.time的许多功能是back-ported to Java 6 & 7further adapted for Android

对于没有日期和时区的仅日期值,请使用LocalDate类。在不存储时区的同时,确定日期(例如“ today”)需要一个时区。如果省略,则会应用JVM的当前默认时区(请注意,该默认时区可以在运行时随时更改)。

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


您似乎想要第一天的时刻。不要假设那一刻的时间是00:00:00.0。尽管通常是这样,但在某些时区中,诸如夏令时之类的异常可能会转移到另一个时间。让java.time确定正确的时间。调用[atStartOfDay][2]会在适合于指定时区的第一时刻生成一个ZonedDateTime

ZonedDateTime zdt = today.atStartOfDay( zoneId );


我强烈建议您不要将日期时间值用作从-epoch的计数。这就像使用Unicode代码点的整数数组,而不是使用与String相关的类来处理文本。但是,如果您坚持要求,可以进行转换。但是要当心数据丢失,因为java.time类具有更好的纳秒分辨率,而您要求的是毫秒(避免将日期时间作为从大数开始进行计数的许多原因之一)。首先在时间轴上以纳秒的分辨率提取Instant,即UTC时间轴上的时刻。

Instant instant = zdt.toInstant();
long millisecondsFromEpoch = instant.toEpochMilli(); // WARNING: Possible data loss (going from nanoseconds to milliseconds).


世界标准时间

如果您确实想要UTC的第一时间,那也很容易。

您可以使用常量ZoneOffset.UTC将UTC指定为时区。 (该常数恰好在ZoneOffset的子类ZoneId中。)

ZonedDateTime zdt = today.atStartOfDay( ZoneOffset.UTC );


但这可能不是最合适的方法。时区是offset-from-UTC加上一组异常规则,例如Daylight Saving Time (DST)。根据定义,UTC没有此类异常。因此,更合适的是OffsetDateTime而不是ZonedDateTime

OffsetTime ot = OffsetTime.of( 0 , 0 , 0 , 0 , ZoneOffset.UTC );
OffsetDateTime odt = today.atTime( ot );

10-05 20:54
查看更多