我对当前 UTC 时间的毫秒数不感兴趣,我也不需要弄乱时区。我的原始日期已存储为 UTC 时间戳。
我在 UTC 时间的数据库中存储了一个日期,“2012-06-14 05:01:25”。我对日期时间不感兴趣,而只是它的日期部分。因此,在 Java 中检索日期并排除小时、分钟和秒后 - 我留下了“2012-06-14”。
如何将其转换为 UTC 毫秒?
我对当前 UTC 时间的毫秒数不感兴趣,我也不需要弄乱时区。我的原始日期已存储为 UTC 时间戳。
我在 UTC 时间的数据库中存储了一个日期,“2012-06-14 05:01:25”。我对日期时间不感兴趣,而只是它的日期部分。因此,在 Java 中检索日期并排除小时、分钟和秒后 - 我留下了“2012-06-14”。
如何将其转换为 UTC 毫秒?
编辑:我错过了“忽略一天中的时间”部分。它现在存在,但接近尾声......
最简单的方法可能是使用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
不是线程安全的,而DateTimeFormatter
is:
// 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 个字符没问题就盲目地继续。
更新:在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格式,但我们需要将 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'.
我正在提供现代答案。这些天(以及过去几年)您应该使用现代 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 中的类型是dateTime
或timestamp
没有时区,我们可能需要检索一个LocalDateTime
来代替(详细信息取决于您的 JDBC 驱动程序和数据库会话的时区)。它以同样的方式进行。要将您的转换LocalDateTime
为OffsetDateTime
,请参阅下面的转换。
如果您无法避免将 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
将 Date 对象与 SimpleDateFormat 结合使用。
Date 中有一个名为 getTime() 的方法,它将为您返回毫秒数。
解决您的问题的示例:
Date truc = new SimpleDateFormat( "y-m-d").parse( "2010-06-14");
System.out.println(truc.getTime());
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);
这里有两种方法:
我使用一种简单直接的方法:
Date date = new Date(utcDateInString);
long utcDateInMilliSeconds = date.getTime();