将Java格式的yyyy-MM-dd'T'HH:mm:ss.SSSz转换为yyyy-mm-dd HH:mm:ss。

86

我正在尝试将格式为yyyy-MM-dd'T'HH:mm:ss.SSSz的日期格式化成yyyy-mm-dd HH:mm:ss,这应该很容易,但我无法让它工作。

需要解析的日期格式如下:2012-10-01T09:45:00.000+02: 00
现在我使用这个简单的日期格式化程序进行格式化:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSz", Locale.FRANCE);

然而,这将生成类似于2012-10-01T09:45:00.000UTC+00:00的输出。

我还尝试使用“yyyy-MM-dd'T'HH:mm:ss.SSSZ”作为模式和“yyyy-MM-ddHH:mm:ss”。后者返回的日期形式接近于2012-10-01T09:45:00,但还不够完整。

我想去掉T子字符串会有点混乱,并且没有必要增加额外的开销,因此什么是格式化这些日期的正确方法呢?

为了说明,我想将2012-10-01T09:45:00.000+02:00转换为2012-10-01 09:45:00

干杯!


字符串截取比转换日期对象要快/简单得多。您只需将原始字符串分成两个子字符串(固定偏移量),然后用空格连接在一起即可。 - Hot Licks
为什么会这样?我可能需要一次解析100多个日期。 - Gooey
你觉得使用两个硬编码偏移量的子字符串操作再加上几个连接操作会比构造和执行两个日期格式化程序更快吗? - Hot Licks
2
FYI,老旧的日期时间类(如java.util.Datejava.util.Calendarjava.text.SimpleTextFormat)现在已经成为遗留系统,被Java.time类所取代。 - Basil Bourque
9个回答

112
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
SimpleDateFormat output = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(time);
String formattedTime = output.format(d);

这个方法可行。你需要使用两个SimpleDateFormat,一个用于输入,一个用于输出,但它会给你想要的结果。


它在开头附加了12...我期望的日期是02/05/2017,但它给了我122/05/2017。 - VVB

42

java.time

我们有针对此问题的新技术:Java 8及更高版本中内置的java.time框架。
您的输入字符串采用标准的ISO 8601格式。该标准是java.time类默认用于解析/生成日期时间值的文本表示形式。
OffsetDateTime odt = OffsetDateTime.parse( "2012-10-01T09:45:00.000+02:00" );

你的问题表明你想截取整秒。
OffsetDateTime odtTruncatedToWholeSecond = odt.truncatedTo( ChronoUnit.SECONDS );

看起来您想省略偏移量和时区信息。预定义的格式化程序 DateTimeFormatter.ISO_LOCAL_DATE_TIME 可以实现此功能。

显然,您想在中间使用空格而不是标准的T。您可以为此定义自己的格式化程序,但我建议只需进行字符串操作将T替换为一个空格即可。

String output = odtTruncatedToWholeSecond.format( DateTimeFormatter.ISO_LOCAL_DATE_TIME ).replace( "T" , " " );

简单的字符串操作

正如问题的评论所建议的那样,严格来说,您可以仅使用字符串而不转换为任何日期时间对象来实现您的目标。但我在这里提供此答案,假设您可能有其他业务逻辑要处理这些日期时间值。


Table of date-time types in Java, both modern and legacy


关于java.time

java.time框架已被内置于Java 8及以后版本。这些类取代了老旧且麻烦的遗留日期时间类,如java.util.Date, CalendarSimpleDateFormat

Joda-Time 项目现在处于 维护模式,建议迁移到 java.time 类。

想要了解更多,请参阅 Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范为 JSR 310

您可以直接使用 java.time 对象与数据库进行交换。使用符合 JDBC 4.2 或更高版本的 JDBC 驱动程序。无需字符串,也不需要 java.sql.* 类。

如何获取 java.time 类?

Table of which java.time library to use with which version of Java or Android

ThreeTen-Extra项目扩展了java.time,提供了额外的类。该项目是java.time可能未来添加的潜在地试验场。您可以在此处找到一些有用的类,例如Interval, YearWeek, YearQuarter更多


1
仅适用于Java 8或更高版本。 - Sangram Badi
2
@Sangram 实际上不仅仅是Java 8。许多java.time功能在ThreeTen-Backport项目中被回溯到Java 6和Java 7,并在ThreeTenABP项目中进一步适用于Android。 - Basil Bourque
当启用解糖时,您可以在较低的Android API上使用标准的java.time(不使用ThreeTen)。请查看此答案:https://dev59.com/7lMI5IYBdhLWcg3wsduA#61218004 - mtrakal

12

如果在您的项目中可以使用Joda Time,那么这段代码适用于我:

String dateStr = "2012-10-01T09:45:00.000+02:00";
String customFormat = "yyyy-MM-dd HH:mm:ss";

DateTimeFormatter dtf = ISODateTimeFormat.dateTime();
LocalDateTime parsedDate = dtf.parseLocalDateTime(dateStr);

String dateWithCustomFormat = parsedDate.toString(DateTimeFormat.forPattern(customFormat));
System.out.println(dateWithCustomFormat);

2
增加不必要的依赖项。它已经存在于JDK中,参见Chris Tate的答案。 - Aubin
我认为它可以在Java 8中运行,但不适用于Java 7或更低版本。 - Sangram Badi
@Sam,它可以在任何Java版本中工作,因为它使用joda-time库。只需将其导入到您的项目中并导入所需的依赖项即可。 - moleksyuk
如何拆分以下格式 String todayDate = currentDate1.toString("yyyy-MMMM-dd HH:mm") - Palak Soni

4

试一下

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

SimpleDateFormat output = new SimpleDateFormat("yyyyMMddHHmmss");

Date d = sdf.parse("2021-09-23T22:05:18.884Z");

String formattedTime = output.format(d);

System.out.println(formattedTime);

结果:20210923220518


1
请不要教年轻人使用早已过时且臭名昭著的SimpleDateFormat类。至少不要将其作为首选项。而且不要毫无保留地使用它。我们在java.time,现代Java日期和时间API中有更好的选择,以及它的DateTimeFormatter - Ole V.V.
我按照你的鼓励尝试了。根据你的代码,我本应得到 20210922072818,因为原始字符串是在UTC时间,而我的时区比UTC提前2个小时。但实际上我得到了 2021092650509884。多出了两位数字,而且日期、小时、分钟和秒钟都不正确。 - Ole V.V.
@OleV.V. 我已经编辑了我的代码,现在你将从中得到你期望的结果。问题在于你期望从这个格式 yyyyMMddHHmmss 得到的结果格式。 - codeAman
更近了,但它仍然没有给我我的时区的时间。 - Ole V.V.

2

我试图格式化从JSON响应收到的日期字符串,例如2016-03-09T04:50:00-0800,以yyyy-MM-dd的格式呈现。下面是我尝试过并且成功的方法,它帮助我为日历小部件分配了格式化的日期字符串。

String DATE_FORMAT_I = "yyyy-MM-dd'T'HH:mm:ss";
String DATE_FORMAT_O = "yyyy-MM-dd";


SimpleDateFormat formatInput = new SimpleDateFormat(DATE_FORMAT_I);
SimpleDateFormat formatOutput = new SimpleDateFormat(DATE_FORMAT_O);

Date date = formatInput.parse(member.getString("date"));
String dateString = formatOutput.format(date);

这个方法可行。谢谢。


1
这个回答没有解决问题的具体细节,而且它重复了三年前被接受的答案的想法。所以我认为它没有任何价值。很高兴看到你想参与Stack Overflow。但是你的答案必须解决问题的具体细节,不能是重复的。 - Basil Bourque

2
如果你真的需要快速(虽然我不认为你需要):
char[] chars = sourceDate.toCharArray();
chars[10] = ' ';
String targetDate = new String(chars, 0, 19);

2
String dateStr = "2016-09-17T08:14:03+00:00";
String s = dateStr.replace("Z", "+00:00");
s = s.substring(0, 22) + s.substring(23);
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(s);
Timestamp createdOn = new Timestamp(date.getTime());
mcList.setCreated_on(createdOn);

Java 7增加了对ISO 8601时区描述符的支持。这可以在Java 7中使用。


1

我有一个案例,需要将一个遗留的DB2 z/os数据库时间戳(格式为:"yyyy-MM-dd'T'HH:mm:ss.SSSZ")转换成SqlServer 2016 datetime2(格式为:"yyyy-MM-dd HH:mm:ss.SSS)字段,并由我们的Spring/Hibernate Entity Manager实例处理(在这种情况下,是OldRevision表)。在类中,我将日期定义为java.util类型,并以正常方式编写setter和getter。然后,在处理数据时,处理与此问题相关的代码如下:

OldRevision revision = new OldRevision();
String oldRevisionDateString= oldRevisionData.getString("originalRevisionDate", "");
Date oldDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSZ");
oldDateFormat.parse(oldRevisionDateString);
SimpleDateFormat newDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
newDateFormat.setTimeZone(TimeZone.getTimeZone("EST"));
Date finalFormattedDate= newDateFormat.parse(newDateFormat.format(oldDateFormat));
revision.setOriginalRevisionDate(finalFormattedDate);
em.persist(revision);

一种更简单的方法是:

SimpleDateFormat newDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
newDateFormat.setTimeZone(TimeZone.getTimeZone("EST"));
revision.setOriginalRevisionDate(
        newDateFormat.parse(newDateFormat.format(
                new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSZ")
                        .parse(rs.getString("originalRevisionDate", "")))));

0
尝试以下代码。
public static void main(String[] args) {
    String str = "18-09-22 02:40:16";
    DateTimeFormatter df = DateTimeFormatter.ofPattern("dd-MM-yy HH:mm:ss", Locale.UK);
    LocalDateTime parse = LocalDateTime.parse(str, df);
    System.out.println("old output = " + parse);
    String output = parse.format( DateTimeFormatter.ISO_LOCAL_DATE_TIME ).replace( "T" , " " );
    System.out.println("output = " + output);
}

这个有效。

输出:

enter image description here


1
在那里,您不需要Locale,因为输入字符串中没有本地化内容。并不是说它有害。 - Basil Bourque
1
你没有回答问题。问题是关于带有UTC偏移量的输入字符串的。你的回答忽略了偏移量。 - Basil Bourque
你是对的,Basil。 - Fazal Haroon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接