在Java中将字符串按不同格式转换为日期

98

我想要将String类型的数据以不同的格式转换为Date类型。

例如,

我从用户那里获取的数据是,

String fromDate = "19/05/2009"; // i.e. (dd/MM/yyyy) format

我想将这个fromDate转换为一个"yyyy-MM-dd"格式的日期对象。

我该怎么做?


2
一个日期对象没有格式,它只是代表日期的数字。日期可以用"yyyy-MM-dd"格式的字符串表示。 - user85421
1
你不能创建一个格式化的日期对象。 - Arvind Kumar Avinash
10个回答

194

可以看一下SimpleDateFormat。代码大致如下:

SimpleDateFormat fromUser = new SimpleDateFormat("dd/MM/yyyy");
SimpleDateFormat myFormat = new SimpleDateFormat("yyyy-MM-dd");

try {

    String reformattedStr = myFormat.format(fromUser.parse(inputString));
} catch (ParseException e) {
    e.printStackTrace();
}

1
我可以获得日期格式的输出,而不是字符串格式吗? - Rachel
4
@Rachel:好的,只需使用 parse 而不要继续使用 formatparse 将字符串解析为日期。 - Michael Myers
3
但是parse返回的是日期格式 Fri Jan 06 00:01:00 EST 2012,但是需要的是 2012-01-06 的日期格式。 - Rachel
1
@Rachel,这是因为当您调用System.out.println(anyDateObject)时,默认的toString()方法被调用,该方法已经被设置为以这种格式打印,例如Fri Jan 06 00:01:00 EST 2012。您需要重写它以适应您的需求。 - KNU
3
FYI,“java.util.Date”、“java.util.Calendar”和“java.text.SimpleDateFormat”等麻烦的老日期时间类现在已经被称为传统系统,并被内置在Java 8和Java 9中的java.time类所取代。请参阅Oracle的教程 - Basil Bourque
显示剩余3条评论

17

简而言之

LocalDate.parse( 
    "19/05/2009" , 
    DateTimeFormatter.ofPattern( "dd/MM/uuuu" ) 
)

详情

使用java.util.Datejava.sql.DateSimpleDateFormat的其他答案现在已经过时。

LocalDate

现代处理日期时间的方式是使用java.time类,特别是LocalDateLocalDate类表示仅包含日期而不包含时间和时区的值。

DateTimeFormatter

要解析或生成表示日期时间值的字符串,请使用DateTimeFormatter类。

DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu" );
LocalDate ld = LocalDate.parse( "19/05/2009" , f );

不要将日期时间对象与表示其值的字符串混淆。日期时间对象没有格式,而字符串有。日期时间对象(例如LocalDate)可以生成一个字符串来表示其内部值,但日期时间对象和字符串是分开的不同对象。
您可以指定任何自定义格式来生成字符串,或让java.time自动本地化工作。
DateTimeFormatter f = 
    DateTimeFormatter.ofLocalizedDate( FormatStyle.FULL )
                     .withLocale( Locale.CANADA_FRENCH ) ;
String output = ld.format( f );

转储到控制台。

System.out.println( "ld: " + ld + " | output: " + output );

ld: 2009年5月19日 | output: 2009年5月19日星期二

在IdeOne.com中查看实例


关于 java.time

java.time 框架是内置于 Java 8 及更高版本的。这些类取代了老旧且令人困扰的 遗留 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

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

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

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

如何获取java.time类?

ThreeTen-Extra项目扩展了java.time的附加类。该项目是java.time可能未来添加的一个试验场。您可能会在这里找到一些有用的类,例如Interval, YearWeek, YearQuarter更多

13

使用SimpleDateFormat类:

private Date parseDate(String date, String format) throws ParseException
{
    SimpleDateFormat formatter = new SimpleDateFormat(format);
    return formatter.parse(date);
}

用法:

Date date = parseDate("19/05/2009", "dd/MM/yyyy");

为了提高效率,您可以将格式化程序存储在哈希映射中。哈希映射是您的实用程序类的静态成员。

private static Map<String, SimpleDateFormat> hashFormatters = new HashMap<String, SimpleDateFormat>();

public static Date parseDate(String date, String format) throws ParseException
{
    SimpleDateFormat formatter = hashFormatters.get(format);

    if (formatter == null)
    {
        formatter = new SimpleDateFormat(format);
        hashFormatters.put(format, formatter);
    }

    return formatter.parse(date);
}

9
注意!这个想法很好,但实现方式不行。日期格式不应该被静态存储,因为它们不是线程安全的!如果它们从多个线程中使用(这在静态情况下总是存在风险),那么就需要注意了。FindBugs包含一个检测器可以发现这个问题(这是我最初贡献的,因为我曾经遇到过这个问题。请参见http://dschneller.blogspot.com/2007/04/calendar-dateformat-and-multi-threading.html :-)) - Daniel Schneller
你的博客文章很有趣 :-) 如果parseDate方法本身是同步的,会怎么样呢?但问题在于这可能会减慢代码的速度... - Agora
1
只要parseDate方法是访问map的唯一方法,同步它就可以工作。然而,正如你所说,这将引入瓶颈。 - Daniel Schneller

8

将字符串日期转换为java.sql.Date

String fromDate = "19/05/2009";
DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
java.util.Date dtt = df.parse(fromDate);
java.sql.Date ds = new java.sql.Date(dtt.getTime());
System.out.println(ds);//Mon Jul 05 00:00:00 IST 2010

5

3

虽然SimpleDateFormat确实可以满足您的需求,但是您可能还想查看Joda Time,它显然是Java 7中重新设计日期库的基础。虽然我没有多次使用过它,但我听到的都是好消息,如果您在项目中广泛处理日期,那么它可能值得一试。


2

格式化日期并将其转换为字符串的简单方法

    Date date= new Date();

    String dateStr=String.format("%td/%tm/%tY", date,date,date);

    System.out.println("Date with format of dd/mm/dd: "+dateStr);

输出:格式为dd/mm/dd的日期:21/10/2015


2
假设你有一个像这样的字符串:
String mDate="2019-09-17T10:56:07.827088"

现在我们想要在Java和Kotlin中将这个字符串格式的日期和时间分开。
JAVA:
我们有一个方法来提取日期:
public String getDate() {
    try {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US);
        Date date = dateFormat.parse(mDate);
        dateFormat = new SimpleDateFormat("MM/dd/yyyy", Locale.US);
        return dateFormat.format(date);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return null;
}

Return是这个:2019年9月17日

我们有提取时间的方法:

public String getTime() {

    try {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US);
        Date date = dateFormat.parse(mCreatedAt);
        dateFormat = new SimpleDateFormat("h:mm a", Locale.US);
        return dateFormat.format(date);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return null;
}

Return是这样的: 上午10:56

KOTLIN:

我们有一个提取日期的函数:

fun getDate(): String? {

    var dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US)
    val date = dateFormat.parse(mDate!!)
    dateFormat = SimpleDateFormat("MM/dd/yyyy", Locale.US)
    return dateFormat.format(date!!)
}

Return是这样的:09/17/2019

我们有提取时间的方法:

fun getTime(): String {

    var dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US)
    val time = dateFormat.parse(mDate!!)
    dateFormat = SimpleDateFormat("h:mm a", Locale.US)
    return dateFormat.format(time!!)
}

Return是这样的: 上午10:56


当我运行你的第二个片段时,我没有得到你所说的10:56 AM,而是得到了11:09 AM(在Oracle jdk-11.0.3上测试)。 - Ole V.V.
@OleV.V.,如果一个方法过时很久了,就会有一条带有标记的线将其弃用。如果一个方法或类没有被弃用,我们就可以使用它。我不是说这是最好的方式,也许我们有更好的方式,但这种方式简单易懂。如果一个方法或类很旧,那么没有理由认为它很麻烦。对于使用DateTimeFormatter,我们需要minsdk 26或更高版本,这并不是好事。 - milad salimi
@OleV.V. 感谢您的评论,关于您的第二条评论,我可以说我在两个应用程序中多次检查它,它返回 10:56 AM - milad salimi
所以显然,在Android上,SimpleDateFormat的行为与桌面Java上的行为有所不同,这种差异令人困惑。 - Ole V.V.
1
@OleV.V.,好的,但是当我没有其他选择或者这个API(库)比我的代码更好时,我会使用一个库。因为当你添加一个库时,你会向你的项目中添加一些可能不会被使用的代码,这会给你的项目带来负担。这是我的方法,而你的方法也值得尊重。 - milad salimi
显示剩余2条评论

1
一个Date对象没有格式,它是一个表示。可以使用您喜欢的格式通过String来呈现日期。

例如"yyyy-MM-dd", "yy-MMM-dd", "dd-MMM-yy"等。

要实现这一点,您可以使用SimpleDateFormat

试试这个:

        String inputString = "19/05/2009"; // i.e. (dd/MM/yyyy) format

        SimpleDateFormat fromUser = new SimpleDateFormat("dd/MM/yyyy"); 
        SimpleDateFormat myFormat = new SimpleDateFormat("yyyy-MM-dd");

        try {
            Date dateFromUser = fromUser.parse(inputString); // Parse it to the exisitng date pattern and return Date type
            String dateMyFormat = myFormat.format(dateFromUser); // format it to the date pattern you prefer
            System.out.println(dateMyFormat); // outputs : 2009-05-19

        } catch (ParseException e) {
            e.printStackTrace();
        }

这段文字的意思是:输出结果为2009年5月19日。

0

有多种方法可以做到这一点,但一个非常实用的方法是使用 String.format,你可以与 java.util.Datejava.util.Calendar 或甚至是 java.time.LocalDate 一起使用。

String.format 的支持者是 java.util.Formatter

我喜欢对它的万物皆可食的看法。

class Playground {
    public static void main(String[ ] args) {
        String formatString = "Created on %1$td/%1$tm/%1$tY%n";
        System.out.println(String.format(formatString, new java.util.Date()));
        System.out.println(String.format(formatString, java.util.Calendar.getInstance()));
        System.out.println(String.format(formatString, java.time.LocalDate.now()));
    }
}

输出结果将始终如一:

Created on 04/12/2022

Created on 04/12/2022

Created on 04/12/2022

有时候那可能会有用,但是你回答的不是一个不同的问题吗?如果我正确理解了 OP 的话,他们想要一个旧式的 Date 对象作为结果。 - Ole V.V.
@OleV.V. 我的回答包括 java.util.Date 对象(请参见上文)。虽然我还包括了其他一些日期类型以突出该方法的实用性,这可能超出了问题的范围,但在更大的视角下,对开发人员来说也是有用的知识。 - gil.fernandes
我完全同意现在我们应该优先使用现代的LocalDate而不是设计不佳的DateCalendar类,所以感谢您包含了它。 - Ole V.V.

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