我对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
部分来执行此操作。
非常感谢任何帮助或建议。
由于
答案 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);
旧类(Date
,Calendar
和SimpleDateFormat
)有lots of problems和design 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_Paulo
或Europe/Berlin
。
避免使用3个字母的缩写(例如CST
或PST
),因为它们是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();