Java - SimpleDateFormat格式化程序,以毫秒为单位返回纪元时间

时间:2017-07-19 11:58:05

标签: java date datetime timestamp epoch

我对Java和编码非常陌生 - 我有一些代码会返回以下格式yyyy.MM.dd HH:mm:ss:ms的时间戳,如下所示:

SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:sss");

返回:

2017.07.19 11:42:30:423

有没有办法编辑上面的“SimpleDateFormat格式化程序”代码,将日期/时间作为包含毫秒的纪元时间戳返回,以便返回的值按照下面的格式进行格式化?

1500464550423

我希望我可以修改("yyyy.MM.dd HH:mm:ss:sss")代码的SimpleDateFormat formatter部分来执行此操作。

非常感谢任何帮助或建议。

由于

6 个答案:

答案 0 :(得分:4)

在格式模式字符串中使用大小写时遇到一个简单错误(这些区分大小写)。更糟糕的是,你正在使用旧的和麻烦的SimpleDateFormat类。其中一个问题是它没有告诉你问题是什么。

所以我建议您使用现代Java日期和时间API(我故意使用您的格式模式字符串逐字):

    String receivedTimetamp = "2017.07.19 11:42:30:423";
    DateTimeFormatter parseFormatter
            = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:sss");
    LocalDateTime dateTime = LocalDateTime.parse(receivedTimetamp, parseFormatter);
    System.out.println(dateTime);

此代码抛出IllegalArgumentException: Too many pattern letters: s。我希望这可以让你意识到这样一个事实,即你使用的是两秒钟的秒数和三秒钟的秒数。如果仍然不清楚,the documentation会告诉您小写s在几秒钟内是正确的,而分数需要大写S。我们来修理:

    DateTimeFormatter parseFormatter
            = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:SSS");

现在代码打印2017-07-19T11:42:30.423,因此我们设法正确解析了字符串。

要转换为毫秒,我们仍然缺少一条至关重要的信息:在什么时区应该解释时间戳?我认为两个明显的猜测是UTC和你当地的时区(我不知道)。试试UTC:

    System.out.println(dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli());

这会产生1500464550423,这是您要求的号码。我想我们已经完成了。

如果您想要改为JVM的时区设置,请使用.atZone(ZoneId.systemDefault())而不是.atOffset(ZoneOffset.UTC),但要注意该设置可能会被同一JVM中运行的其他软件更改,因此这很脆弱。 / p>

答案 1 :(得分:2)

首先,检查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

旧类(DateCalendarSimpleDateFormat)有lots of problemsdesign issues,它们将被新API取代。< / p>

如果您使用的是 Java 8 ,请考虑使用new java.time API。它更容易,less bugged and less error-prone than the old APIs

如果您使用的是 Java&lt; = 7 ,则可以使用ThreeTen Backport,这是Java 8新日期/时间类的绝佳后端。对于 Android ,有ThreeTenABP(更多关于如何使用它here)。

以下代码适用于两者。 唯一的区别是包名称(在Java 8中为java.time,在ThreeTen Backport(或Android的ThreeTenABP)中为org.threeten.bp),但类和方法名称是相同的

由于输入String没有时区信息(仅限日期和时间),首先我将其解析为LocalDateTime(表示没有时区的日期和时间的类)。然后我将此日期/时间转换为特定时区并从中获取millis值:

// 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_PauloEurope/Berlin。 避免使用3个字母的缩写(例如CSTPST),因为它们是ambiguous and not standard

您可以致电ZoneId.getAvailableZoneIds()获取可用时区列表(并选择最适合您系统的时区)。

如果您想使用UTC,也可以使用ZoneOffset.UTC常量。

相反,您可以获取millis值来创建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);

答案 2 :(得分:1)

如果您有java.util.Date,则调用getTime()将返回自纪元以来的millis数。例如:

SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:sss");

Date dateToBeFormatted = new Date();

// this will print a datetime literal on the above format
System.out.println(formatter.format(dateToBeFormatted));

// this will print the number of millis since the Java epoch
System.out.println(dateToBeFormatted.getTime());

这里的关键点是,为了获得自纪元以来的毫秒数,您不需要SimpleDateFormatter,因为自纪元以来的毫秒数是Date的属性。 / p>

答案 3 :(得分:1)

第一个建议是转移到java8 java.time API,而不是学习损坏的java.date API

然后做:

Instant i = Instant.now();
System.out.println(i.toEpochMilli());

在你的情况下,你可以这样做:

LocalDateTime myldt = LocalDateTime.parse("2017-06-14 14:29:04",
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println(myldt.toInstant(ZoneOffset.UTC).toEpochMilli());

请注意,只要您使用api玩更多内容,您就会找到更多方法来实现同样的目标,最后您将结束调用toEpochMilli

答案 4 :(得分:1)

    String strDate = "Jun 13 2003 23:11:52.454 UTC";
    DateTimeFormatter dtf  = DateTimeFormatter.ofPattern("MMM dd yyyy HH:mm:ss.SSS zzz");
    ZonedDateTime     zdt  = ZonedDateTime.parse(strDate,dtf);        
    System.out.println(zdt.toInstant().toEpochMilli());  // 1055545912454  

答案 5 :(得分:1)

你可以尝试

long time = System.currentTimeMillis();