10

我对当前 UTC 时间的毫秒数不感兴趣,我也不需要弄乱时区。我的原始日期已存储为 UTC 时间戳。

我在 UTC 时间的数据库中存储了一个日期,“2012-06-14 05:01:25”。我对日期时间不感兴趣,而只是它的日期部分。因此,在 Java 中检索日期并排除小时、分钟和秒后 - 我留下了“2012-06-14”。

如何将其转换为 UTC 毫秒?

4

6 回答 6

14

编辑:我错过了“忽略一天中的时间”部分。它现在存在,但接近尾声......

最简单的方法可能是使用SimpleDateFormat,适当地设置时区:

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));

Date date = format.parse(text);
long millis = date.getTime();

(设置时区在这里很重要,否则它会将值解释为本地时区。)

或者,如果您做的事情比这更简单,请使用Joda Time,它是一个更好的日期/时间 API。特别是,SimpleDateFormat 不是线程安全的,而DateTimeFormatteris:

// This can be reused freely across threads after construction.
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
    .withLocale(Locale.US)
    .withZoneUTC();

// Option 1
DateTime datetime = formatter.parseDateTime(text);
long millis = dateTime.getMillis();

// Option 2, more direct, but harder to diagnose errors
long millis = formatter.parseMillis(text);

到目前为止,我们已经解析了整个堆。忽略日期部分的最简单方法就是将其四舍五入 - 毕竟,Java 不遵守闰秒,所以我们可以截断它:

long millisPerDay = 24L * 60L * 60L * 1000L; // Or use TimeUnit
long dayMillis = (millis / millisPerDay) * millisPerDay;

这将“朝 1970 年四舍五入”,因此如果您的日期1970 年之前,它将四舍五入到一天结束- 但我怀疑这不太可能成为问题。

使用 Joda Time 版本,您可以改用它:

DateTime dateTime = formatter.parseDateTime(text);
long millis = dateTime.toLocalDate().getLocalMillis();

我个人不会接受仅采用子字符串的想法。即使您实际上对保留小时/分钟/秒并不感兴趣,但我认为解析您所获得的内容然后丢弃信息是合适的。除此之外,它会使您的代码因错误数据而适当失败,例如

"2012-06-100"

或者

"2012-06-14 25:01:25"

指出为您提供数据的任何问题,最好发现这一点,而不是仅仅因为前 10 个字符没问题就盲目地继续。

于 2012-08-22T21:12:31.500 回答
2

更新:在Ole VV的正确答案中查看使用java.time类的现代解决方案。

更简单

Jon Skeet的回答是正确的。他提出了一个很好的观点,即在解析时包含而不是截断时间信息。

但是,他的代码可以简化。尤其是因为Joda-Time在最新版本中获得了一个重要的新方法:withTimeAtStartOfDay. 此方法取代了现在已弃用的所有与“午夜”相关的类和方法。

指定一个Locale是一个好习惯,如他的代码所示。但在这种特殊情况下,不需要 Locale。

他的回答正确地暗示了 Joda-Time 库,远远优于使用 java.util.Date、.Calendar 和 java.text.SimpleTextFormat。这些课程是出了名的麻烦,应该避免。而是使用 Joda-Time 或 Java 8 中内置的新java.time 包(受 JSR 310 定义的 Joda-Time 启发)。

一天的第一刻

如果您想要的是自纪元以来的毫秒数,则您不能忽略时间。我怀疑您想要的是将时间更改为一天中的第一刻。在 UTC 中,这始终表示时间00:00:00.000但请注意,在当地时区,由于夏令时和可能的其他异常情况,第一时刻可能是不同的时间。

ISO 8601

您的字符串几乎采用标准ISO 8601格式,但我们需要将 a 换成T中间的 SPACE。然后我们可以将生成的字符串直接提供给 Joda-Time,因为 Joda-Time 具有默认用于标准字符串的内置格式化程序。

示例代码

以下示例代码假定您的问题的目的是将字符串解析为UTC时区中的日期时间值,将时间调整为一天中的第一刻,然后转换为自Unix 纪元以来的毫秒数(开始1970 年 UTC)。

String inputRaw = "2012-06-14 05:01:25";
String input = inputRaw.replace( " ", "T" );  // Replace SPACE with a 'T'.
DateTime dateTime = new DateTime( input, DateTimeZone.UTC );  // Parse, assuming UTC.
DateTime dateTimeTopOfTheDay = dateTime.withTimeAtStartOfDay();  // Adjust to first moment of the day.
long millisecondsSinceUnixEpoch = dateTimeTopOfTheDay.getMillis();  // Convert to millis. Use a 'long', not an 'int'.
于 2014-10-08T06:39:27.963 回答
1

java.time 和 JDBC 4.2

我正在提供现代答案。这些天(以及过去几年)您应该使用现代 Java 日期和时间 API java.time 来进行日期和时间工作。从 JDBC 4.2 开始,您可以直接从数据库中检索 java.time 对象(并将它们存储到其中)。现代的 JPA 实现(至少从 Hibernate 5 开始是 Hibernate)将很乐意这样做。所以忘记SimpleDateFormat,Date和大多数旧答案中使用的其他旧类。上面提到的设计很糟糕,而 java.time 使用起来更好。

从数据库中检索正确的日期时间对象

我还建议您不要将 UTC 时间作为字符串从数据库中检索。如果 SQL 中的数据类型是timestamp with time zone(推荐用于 UTC 时间),则检索OffsetDateTime. 例如:

    PreparedStatement pStmt = yourDatabaseConnection
            .prepareStatement("select utc_time from your_table where id = 7;");
    ResultSet rs = pStmt.executeQuery();
    if (rs.next()) {
        OffsetDateTime utcDateTime = rs.getObject("utc_time", OffsetDateTime.class);
        long millisecondsSinceEpoch = utcDateTime.truncatedTo(ChronoUnit.DAYS)
                .toInstant()
                .toEpochMilli();
        System.out.println("Milliseconds since the epoch: " + millisecondsSinceEpoch);
    }

如果 SQL 中的类型是dateTimetimestamp没有时区,我们可能需要检索一个LocalDateTime来代替(详细信息取决于您的 JDBC 驱动程序和数据库会话的时区)。它以同样的方式进行。要将您的转换LocalDateTimeOffsetDateTime,请参阅下面的转换。

如果您需要从字符串转换

如果您无法避免将 UTC 时间作为问题中的字符串,请将其解析为 aLocalDateTime并从那里转换。例如:

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
    String utcTimeString = "2012-06-14 05:01:25";
    long millisecondsSinceEpoch = LocalDateTime.parse(utcTimeString, formatter)
            .atOffset(ZoneOffset.UTC)
            .toInstant()
            .toEpochMilli();
    System.out.println("Milliseconds since the epoch: " + millisecondsSinceEpoch);

输出:

自纪元以来的毫秒数:1339650085000

关联

于 2020-03-30T05:53:20.230 回答
0

将 Date 对象与 SimpleDateFormat 结合使用。

Date 中有一个名为 getTime() 的方法,它将为您返回毫秒数。

解决您的问题的示例:

Date truc = new SimpleDateFormat( "y-m-d").parse( "2010-06-14");
System.out.println(truc.getTime());
于 2012-08-22T21:10:18.673 回答
0
SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd"); //or whatever format you have
Date t = ft.parse('2014-03-20');

String result = String.format("%tQ", t);

System.out.printf("%tQ", t);

这里有两种方法:

  1. 您将结果毫秒放入变量结果中
  2. 直接打印出来。
于 2014-10-07T22:38:10.337 回答
-1

我使用一种简单直接的方法:

Date date = new Date(utcDateInString);
long utcDateInMilliSeconds = date.getTime();
于 2015-02-10T22:34:31.837 回答