我想将2018-02-21 15:47:35
UTC转换为世纪UTC形式。我们该怎么做呢?我目前在太平洋标准时间。
SimpleDateFormat df = new SimpleDateFormat("YYYY-MM-DD HH:MM:SS");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
date = df.parse(dateString).getTime();
上面的代码应该返回自January 1, 1970, 00:00:00 GMT
以来的毫秒数,但是我得到的值不正确。
您的代码唯一的问题是DateFormat
请检查。 https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
String dateString = "2018-02-21 15:47:35";
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = df.parse(dateString);
long time = date.getTime();
System.out.println(time);
System.out.println(new Date(time));
System.out.println(date);
我在PKT,所以输出会有所不同......
1519228055000
Wed Feb 21 20:47:35 PKT 2018
Wed Feb 21 20:47:35 PKT 2018
预计:2018-02-21 15:47:35 UTC相当于自1970年1月1日0:00 UTC时代以来的1 519 228 055 000毫秒。
观察到:你问题中的代码给出1 514 818 800 035.所以它是4 409 254 965毫秒关闭,超过51天。
解决方案:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
date = LocalDateTime.parse("2018-02-21 15:47:35", dtf)
.atOffset(ZoneOffset.UTC)
.toInstant()
.toEpochMilli();
这给出了正确的1 519 228 055 000。
什么地方出了错?
SimpleDateFormat
的许多麻烦特征之一是,使用其默认设置,如果指定了不正确的格式模式字符串,它通常会给你一个不正确的结果,并假装一切都很好。我在我的代码片段中使用的现代Java日期和时间API正在尝试更难以弄清楚模式何时没有意义并告诉你它在某种程度上是错误的。举个例子,让我们用现代的DateTimeFormatter
尝试你的格式模式:
final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("YYYY-MM-DD HH:MM:SS");
LocalDateTime.parse(dateString, dtf);
这会抛出一个java.time.format.DateTimeParseException: Text '2018-02-21 15:47:35' could not be parsed at index 14
。索引14是字符串中的47,它应该是分钟。显然47与格式中的MM
不匹配。如果您还没有想出来,请查看文档。它说大写的M
是“年月”。那么格式化程序试图告诉你的是一年中没有47个月。在文档中,您还可以找到“小时”的小写m
。当您更正格式模式字符串中字母的大小写时,您将收到其他例外,直到您最终得到yyyy-MM-dd HH:mm:ss
或uuuu-MM-dd HH:mm:ss
(小写yyyy
是年份或时代,而uuuu
是签名年份,都在0年后工作多年) 。
链接
java.time
。DateTimeFormatter
documentation拼写出格式模式字符串的大写和小写字母。也可以通过java8时间库来完成:
String dateString = "2018-02-21 15:47:35";
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
dateTimeFormatter.withZone(ZoneId.of("UTC"));
LocalDateTime parsedDateTime = LocalDateTime.from(dateTimeFormatter.parse(dateString));
ZonedDateTime timeAtYourZone = parsedDateTime.atZone(ZoneId.systemDefault());
System.out.println(timeAtYourZone.toInstant().toEpochMilli());
System.out.println(timeAtYourZone);
你的模式必须是yyyy-MM-dd HH:mm:ss
,其他答案告诉你:
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
我只是想补充一些细节。
首先,看一下javadoc中的模式描述:https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
请注意,小写y与大写Y不同(小写是年份,而大写是week year - 2个不同的字段,定义完全不同)
另请注意,大写的D是一年中的某一天,而月份的日期(这是您想要的)是小写的d。大写字母M是月份,而小写字母m是小时分钟。
大写字母S是毫秒字段,而秒数由小写字母s表示。
并且SimpleDateFormat
的设计没有帮助:该类只是尝试解析字符串,即使月份字段(MM)在您的模式中出现两次,而分钟字段没有出现(并且它被设置为默认值零 - 所有幕后,没有任何警告,根本没有错误的迹象)。
结论:总是阅读文档:-)
对于Java 8或更高版本,请考虑使用新的日期API,它更好,因为它没有所有这些幕后的东西:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
.withZone(ZoneOffset.UTC);
long epochMilli = Instant.from(fmt.parse("2018-02-21 15:47:35")).toEpochMilli();
如果你使用像YYYY-MM-DD HH:MM:SS
这样的模式,这个API也会抛出异常,因为它会尝试将分钟值47解析为月份(因为大写的MM将在相应的位置),而47不是有效的月份。