Java - SimpleDateFormat 格式化程序以毫秒为单位返回纪元时间
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/45189859/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java - SimpleDateFormat formatter to return epoch time with milliseconds
提问by Mark Smith
I am very new to Java and coding in general - I have some code which returns a timestamp in the following format yyyy.MM.dd HH:mm:ss:ms
which is shown below:
我对 Java 和一般编码非常陌生 - 我有一些代码以以下格式返回时间戳,如下yyyy.MM.dd HH:mm:ss:ms
所示:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:sss");
This returns:
这将返回:
2017.07.19 11:42:30:423
Is there a way to edit the "SimpleDateFormat formatter" code above to return the date/time as an epoch timestamp that includes milliseconds so that the value returned is formatted as per the below?
有没有办法编辑上面的“SimpleDateFormat 格式化程序”代码以将日期/时间作为包含毫秒的纪元时间戳返回,以便返回的值按照以下格式进行格式化?
1500464550423
I'm hoping that I can amend the ("yyyy.MM.dd HH:mm:ss:sss")
part of the SimpleDateFormat formatter
code to do this.
我希望我可以修改代码的("yyyy.MM.dd HH:mm:ss:sss")
一部分SimpleDateFormat formatter
来做到这一点。
Any help or advice is much appreciated.
非常感谢任何帮助或建议。
Thanks
谢谢
回答by Ole V.V.
You have a simple error in the use of case in your format pattern string (these are case sensitive). And worse, you are using the old and troublesome SimpleDateFormat
class. One of the many problems with it is it's not telling you what the problem is.
您在格式模式字符串中使用 case 时有一个简单的错误(这些是区分大小写的)。更糟糕的是,你正在使用旧的和麻烦的SimpleDateFormat
类。它的众多问题之一是它没有告诉您问题是什么。
So I recommend you use the modern Java date and time API instead (I am deliberately using your format pattern string verbatim):
因此,我建议您改用现代 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);
This code throws an IllegalArgumentException: Too many pattern letters: s
. I hope this calls your awareness to the fact that you are using two s's for seconds and three s's for fraction of second. If it still isn't clear, the documentationwill tell you that lowercase s
is correct for seconds, while you need uppercase S
for the fraction. Let's repair:
此代码抛出一个IllegalArgumentException: Too many pattern letters: s
. 我希望这能让您意识到您使用两个 s 表示几秒钟,三个 s 表示几分之一秒。如果仍然不清楚,文档会告诉您小写s
在几秒钟内是正确的,而您需要大写S
的分数。让我们修复:
DateTimeFormatter parseFormatter
= DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:SSS");
Now the code prints 2017-07-19T11:42:30.423
, so we have managed to parse the string correctly.
现在代码打印了2017-07-19T11:42:30.423
,所以我们已经成功地解析了字符串。
To convert to milliseconds we are still missing a crucial piece of information: in what time zone should the timestamp be interpreted? I think the two obvious guesses are UTC and your local time zone (which I don't know). Try UTC:
要转换为毫秒,我们仍然缺少一个关键信息:时间戳应该在哪个时区解释?我认为两个明显的猜测是 UTC 和您当地的时区(我不知道)。尝试协调世界时:
System.out.println(dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli());
This produces 1500464550423
, which is the number you asked for. I suppose we're done.
这会产生1500464550423
,这是您要求的数字。我想我们已经完成了。
If you wanted your JVM's time zone setting instead, use .atZone(ZoneId.systemDefault())
instead of .atOffset(ZoneOffset.UTC)
, but beware that the setting may be altered by other software running in the same JVM, so this is fragile.
如果您想要 JVM 的时区设置,请使用.atZone(ZoneId.systemDefault())
代替.atOffset(ZoneOffset.UTC)
,但请注意该设置可能会被同一 JVM 中运行的其他软件更改,因此这很脆弱。
回答by Mark Smith
First of all, check the documentation of SimpleDateFormat
. The pattern that corresponds to millisecondsis an uppercaseS
, while the lowercases
corresponds to seconds. The problem is that SimpleDateFormat
usually doesn't complain and try to parse 423
as seconds, adding this amount to your end date (giving an incorrect result).
首先,检查的文件SimpleDateFormat
。对应于毫秒的模式是大写S
,而小写s
对应于秒。问题是SimpleDateFormat
通常不会抱怨并尝试解析423
为秒,将此数量添加到您的结束日期(给出不正确的结果)。
Anyway, SimpleDateFormat
just parses a String
to a java.util.Date
or formats the Date
to a String
. If you want the epoch millis value, you must get it from the Date
object:
无论如何,SimpleDateFormat
只需将 a 解析String
为 ajava.util.Date
或将 a格式化Date
为 a String
。如果你想要纪元毫秒值,你必须从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
The problem is that SimpleDateFormat
uses the system's default timezone, so the final value above (1500475350423
) will be equivalent to the specificed date and time in my system's timezone (which can be different from yours - just for the record, my system's default timezone is America/Sao_Paulo
). If you want to specify in what timezone this date is, you need to set in the formatter (before calling parse
):
问题是SimpleDateFormat
使用系统的默认时区,所以上面的最终值 ( 1500475350423
) 将等同于我系统时区中的特定日期和时间(可能与您的不同 - 只是为了记录,我系统的默认时区是America/Sao_Paulo
)。如果要指定此日期所在的时区,则需要在格式化程序中进行设置(在调用之前parse
):
// set a timezone to the formatter (using UTC as example)
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
With this, the result for millis
will be 1500464550423
(the equivalent to the specificed date and time in UTC).
有了这个,结果millis
将为1500464550423
(相当于 UTC 中的特定日期和时间)。
To do the opposite (create a date from the millis value), you must create a Date
object and then pass it to the formatter (also taking care of setting a timezone to the formatter):
要执行相反的操作(从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 new date/time API
Java 新的日期/时间 API
The old classes (Date
, Calendar
and SimpleDateFormat
) have lots of problemsand design issues, and they're being replaced by the new APIs.
旧类(Date
,Calendar
和SimpleDateFormat
)有很多问题和设计问题,它们正在被新的 API 取代。
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
如果您使用的是Java 8,请考虑使用新的 java.time API。与旧的 API 相比,它更容易、更少被窃听且更不容易出错。
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP(more on how to use it here).
如果您使用的是Java <= 7,则可以使用ThreeTen Backport,这是 Java 8 新日期/时间类的一个很好的向后移植。对于Android,有ThreeTenABP(更多关于如何使用它在这里)。
The code below works for both.
The only difference is the package names (in Java 8 is java.time
and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp
), but the classes and methods namesare the same.
下面的代码适用于两者。唯一的区别是包名(在 Java 8 中是,java.time
而在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是org.threeten.bp
),但类和方法名是相同的。
As the input String
has no timezone information (only date and time), first I parsed it to a LocalDateTime
(a class that represents a date and time without timezone). Then I convert this date/time to a specific timezone and get the millis value from it:
由于输入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
The value is now 1500460950423
, equivalent to the specified date and time in London timezone.
该值是 now 1500460950423
,相当于伦敦时区中的指定日期和时间。
Note that the API uses IANA timezones names(always in the format Region/City
, like America/Sao_Paulo
or Europe/Berlin
).
Avoid using the 3-letter abbreviations (like CST
or PST
) because they are ambiguous and not standard.
请注意,API 使用IANA 时区名称(始终采用 格式Region/City
,如America/Sao_Paulo
或Europe/Berlin
)。避免使用 3 个字母的缩写(如CST
或PST
),因为它们含糊不清且不标准。
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds()
.
您可以通过调用获取可用时区列表(并选择最适合您系统的时区)ZoneId.getAvailableZoneIds()
。
You can also use ZoneOffset.UTC
constant if you want to use UTC.
ZoneOffset.UTC
如果您想使用 UTC,您也可以使用常量。
To do the opposite, you can get the millis value to create an Instant, convert it to a timezone and pass it to the formatter:
相反,您可以获取毫秒值来创建 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);
回答by glytching
If you have a java.util.Date
then invoking getTime()
will return the number of millis since the epoch. For example:
如果你有一个java.util.Date
then 调用getTime()
将返回自纪元以来的毫秒数。例如:
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());
The key point here is that in order to get the number of millis since the epoch you do not need a SimpleDateFormatter
because the number of millis since the epoch is a property of the Date
.
这里的关键是,为了获得自纪元以来的毫秒数,您不需要 aSimpleDateFormatter
因为自纪元以来的毫秒数是Date
.
回答by ΦXoc? ? Пepeúpa ツ
First advice is to move to java8 java.time API instead of learning the broken java.date API
第一个建议是转向 java8 java.time API 而不是学习损坏的 java.date API
then do:
然后做:
Instant i = Instant.now();
System.out.println(i.toEpochMilli());
in your case you can do:
在你的情况下,你可以这样做:
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());
note that as soon as you play more with the api you will find more ways to achieve the same thing, at the end you will end invoking toEpochMilli
请注意,只要您更多地使用 api,您就会找到更多方法来实现相同的目标,最后您将结束调用toEpochMilli
回答by Vilius
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
回答by assembler
You can try
你可以试试
long time = System.currentTimeMillis();