首先,检查documentation of SimpleDateFormat。 毫秒对应的模式是大写S,而小写s对应秒 .问题是SimpleDateFormat 通常不会抱怨并尝试将423 解析为秒,将此数量添加到您的结束日期(给出不正确的结果)。
无论如何,SimpleDateFormat 只是将String 解析为java.util.Date 或将Date 格式化为String。如果你想要 epoch millis 值,你必须从 Date 对象中获取它:
// input string
String s = "2017.07.19 11:42:30:423";
// use correct format ('S' for milliseconds)
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:SSS");
// parse to a date
Date date = formatter.parse(s);
// get epoch millis
long millis = date.getTime();
System.out.println(millis); // 1500475350423
问题是SimpleDateFormat 使用系统的默认时区,因此上面的最终值 (1500475350423) 将等同于我系统时区中的指定日期和时间(可能与您的不同 - 仅用于记录,我系统的默认时区是America/Sao_Paulo)。如果你想指定这个日期在哪个时区,你需要在格式化程序中设置(在调用parse之前):
// set a timezone to the formatter (using UTC as example)
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
这样,millis 的结果将是 1500464550423(相当于 UTC 中的指定日期和时间)。
反之亦然(从 millis 值创建日期),您必须创建一个 Date 对象,然后将其传递给格式化程序(还要注意为格式化程序设置时区):
// create date from millis
Date date = new Date(1500464550423L);
// use correct format ('S' for milliseconds)
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:SSS");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
// format date
String formatted = formatter.format(date);
Java 新日期/时间 API
旧的类(Date、Calendar 和 SimpleDateFormat)有 lots of problems 和 design issues,它们正在被新的 API 取代。
如果您使用的是 Java 8,请考虑使用 new java.time API。更简单,less bugged and less error-prone than the old APIs。
如果您使用的是 Java ,则可以使用 ThreeTen Backport,这是 Java 8 新日期/时间类的一个很好的向后移植。对于Android,还有ThreeTenABP(更多关于如何使用它here)。
下面的代码适用于两者。
唯一的区别是包名(在 Java 8 中是 java.time,而在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp),但类和方法 names 是相同的。
由于输入String 没有时区信息(只有日期和时间),首先我将其解析为LocalDateTime(表示没有时区的日期和时间的类)。然后我将此日期/时间转换为特定时区并从中获取毫秒值:
// input string
String s = "2017.07.19 11:42:30:423";
// use correct format ('S' for milliseconds)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:SSS");
// as the input string has no timezone information, parse it to a LocalDateTime
LocalDateTime dt = LocalDateTime.parse(s, formatter);
// convert the LocalDateTime to a timezone
ZonedDateTime zdt = dt.atZone(ZoneId.of("Europe/London"));
// get the millis value
long millis = zdt.toInstant().toEpochMilli(); // 1500460950423
现在的值为1500460950423,相当于伦敦时区的指定日期和时间。
请注意,API 使用IANA timezones names(始终采用Region/City 格式,如America/Sao_Paulo 或Europe/Berlin)。
避免使用三个字母的缩写(如CST 或PST),因为它们是ambiguous and not standard。
您可以致电ZoneId.getAvailableZoneIds() 获取可用时区列表(并选择最适合您系统的时区)。
如果你想使用 UTC,你也可以使用 ZoneOffset.UTC 常量。
相反,您可以获取毫秒值来创建 Instant,将其转换为时区并将其传递给格式化程序:
// create Instant from millis value
Instant instant = Instant.ofEpochMilli(1500460950423L);
// use correct format ('S' for milliseconds)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:SSS");
// convert to timezone
ZonedDateTime z = instant.atZone(ZoneId.of("Europe/London"));
// format
String formatted = z.format(formatter);