如何在java中获取给定的日期字符串格式(模式)?

Posted

技术标签:

【中文标题】如何在java中获取给定的日期字符串格式(模式)?【英文标题】:How to get the given date string format(pattern) in java? 【发布时间】:2011-11-26 14:41:06 【问题描述】:

我想获取给定日期字符串的格式。

示例:我有一个类似2011-09-27T07:04:21.97-05:00 的字符串,该字符串的日期格式是yyyy-MM-dd'T'HH:mm:ss.SSS

在这里,当我将字符串(2011-09-27T07:04:21.97-05:00)传递给将返回格式(yyyy-MM-dd'T'HH:mm:ss.SSS)的方法时,我想找出这种日期格式,然后我将根据我的要求格式化给定的日期字符串(@ 987654325@)。

谁能告诉我如何才能实现它?

【问题讨论】:

@Tomasz Nurkiewicz,不,不是。这是从一种格式到另一种格式的日期转换问题。 大声笑..我浪费了我的时间滚动这个问题的 javascript 答案..没有用...它不是重复的问题..请取消标记重复 @MingweiSamuel 3 年半后重新开放 【参考方案1】:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class NewClass 

    private static final String[] formats =  
                "yyyy-MM-dd'T'HH:mm:ss'Z'",   "yyyy-MM-dd'T'HH:mm:ssZ",
                "yyyy-MM-dd'T'HH:mm:ss",      "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
                "yyyy-MM-dd'T'HH:mm:ss.SSSZ", "yyyy-MM-dd HH:mm:ss", 
                "MM/dd/yyyy HH:mm:ss",        "MM/dd/yyyy'T'HH:mm:ss.SSS'Z'", 
                "MM/dd/yyyy'T'HH:mm:ss.SSSZ", "MM/dd/yyyy'T'HH:mm:ss.SSS", 
                "MM/dd/yyyy'T'HH:mm:ssZ",     "MM/dd/yyyy'T'HH:mm:ss", 
                "yyyy:MM:dd HH:mm:ss",        "yyyyMMdd", ;

        /*
         * @param args
         */
    public static void main(String[] args) 
        String yyyyMMdd = "20110917";   
        parse(yyyyMMdd);
    

    public static void parse(String d) 
        if (d != null) 
            for (String parse : formats) 
                SimpleDateFormat sdf = new SimpleDateFormat(parse);
                try 
                    sdf.parse(d);
                    System.out.println("Printing the value of " + parse);
                 catch (ParseException e) 

                
            
        
    

【讨论】:

上述解决方案肯定会解析日期,但不会给出日期格式。 SimpleDateFormat 的 toPattern 和 toLocalizedPattern 将给出确切的格式。 如果有人在使用这个解决方案,只需在打印值后返回解析字符串 永远不要将Z 硬编码为格式模式中的文字。这是一个偏移量,需要这样解析,否则你会得到不正确的结果。以及 2020 年的评论:我们不应再使用 DateSimpleDateFormat。这些类设计不佳且早已过时。【参考方案2】:

你可以这样做,我不知道好不好,但试试这个

首先创建 SimpleDateFormat 对象

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

现在检查日期是否会以这种格式解析,然后根据您的格式进行更改

try
     Date date = sdf.parse(yourdate);
     sdf.applyPattern("yy-mm--dd or mm/dd/yyyy");
     String dateformat = sdf.format(date);
catch(Exception ex)  // here forgot the exact exception class Parse exception was used
    // do something here

更新帖子:

Returning a date format from an unknown format of date string in java

How to convert String to Date without knowing the format?

Parse any date in Java

【讨论】:

如何在不知道给定字符串格式的情况下将格式指定为 SimpleDateFormat? 如何在不知道给定字符串格式的情况下将 SimpleDateFormat 的格式指定为“yyyy-mm-dd 'T' HH:mm:ss.SSS”?如果我的字符串像 2011-09-28 12:00:22 那么我应该如何用上面的 SimpleDateFormat 对象解析它?【参考方案3】:

我认为您应该尝试使用一些预定义的模式来解析输入字符串。一个有效的就是你需要的那个。请记住,有些模式非常棘手。

01.12.12 在欧洲是 2012 年 12 月 1 日,但在美国是 2012 年 1 月 12 日。也可能是 2001 年 12 月 12 日。

【讨论】:

【参考方案4】:

如果我理解正确,您想使用DateFormat.parse()任意 字符串(即您不知道的格式的字符串)解析为日期吗?然后你必须处理诸如如何处理01-02-03(2003 年 1 月 2 日?2003 年 2 月 1 日?等等)之类的问题

您至少应该了解一些有关预期格式的信息,例如为您的输入选择几种预定义格式。

【讨论】:

【参考方案5】:

Madhu 的代码可以锻炼,但是会出现一些性能问题,因为每个失败案例都会引发异常。 我认为我们需要找到正则表达式解决方案来找到给定日期字符串的模式。

您可以在以下链接中找到所有大多数日期和时间格式的 reg 表达式

http://regexlib.com/DisplayPatterns.aspx?cattabindex=4&categoryId=5&AspxAutoDetectCookieSupport=1

【讨论】:

【参考方案6】:

您需要获取初始日期字符串并将其转换为日期对象,并将转换后的日期对象传递给您所需的字符串。

【讨论】:

【参考方案7】:

你可以试试dateparser。

它可以自动识别任何String,并将其解析为DateCalendarLocalDateTime >OffsetDateTime正确快速(1us~1.5us)。

它不基于任何natural language analyzerSimpleDateFormatregex.Pattern

有了它,您不必准备任何合适的模式,例如yyyy-MM-dd'T'HH:mm:ss'Z'MM/dd/yyyy HH:mm:ss 等:

Date date = DateParserUtils.parseDate("2015-04-29T10:15:00.500+0000");
Calendar calendar = DateParserUtils.parseCalendar("2015-04-29T10:15:00.500Z");
LocalDateTime dateTime = DateParserUtils.parseDateTime("2015-04-29 10:15:00.500 +00:00");

而且它比循环尝试多个SimpleDateFormat 具有更好的性能。

请尽情享受吧。

【讨论】:

【参考方案8】:

这是一个通用的解决方案,在不事先知道日期模式的情况下确定模式,并且不对所有格式调用SimpleDateFormat 的解析方法。您可以使用正则表达式从日期字符串值中获取任何日期模式。

package com.utility.utils.modelmapper.datetime;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class DateParser 
    private static final Map<String, String> DATE_FORMAT_REGEXPS = new HashMap<String, String>() 
        
            put("^\\d8$", "yyyyMMdd");
            put("^\\d12$", "yyyyMMddHHmm");
            put("^\\d8\\s\\d4$", "yyyyMMdd HHmm");
            put("^\\d14$", "yyyyMMddHHmmss");
            put("^\\d8\\s\\d6$", "yyyyMMdd HHmmss");
            put("^\\d1,2-\\d1,2-\\d4$", "dd-MM-yyyy");
            put("^\\d4-\\d1,2-\\d1,2$", "yyyy-MM-dd");
            put("^\\d1,2/\\d1,2/\\d4$", "MM/dd/yyyy");
            put("^\\d4/\\d1,2/\\d1,2$", "yyyy/MM/dd");
            put("^\\d1,2\\s[a-z]3\\s\\d4$", "dd MMM yyyy");
            put("^\\d1,2\\s[a-z]4,\\s\\d4$", "dd MMMM yyyy");
            put("^\\d1,2-\\d1,2-\\d4\\s\\d1,2:\\d2$", "dd-MM-yyyy HH:mm");
            put("^\\d4-\\d1,2-\\d1,2\\s\\d1,2:\\d2$", "yyyy-MM-dd HH:mm");
            put("^\\d1,2/\\d1,2/\\d4\\s\\d1,2:\\d2$", "MM/dd/yyyy HH:mm");
            put("^\\d4/\\d1,2/\\d1,2\\s\\d1,2:\\d2$", "yyyy/MM/dd HH:mm");
            put("^\\d1,2\\s[a-z]3\\s\\d4\\s\\d1,2:\\d2$", "dd MMM yyyy HH:mm");
            put("^\\d1,2\\s[a-z]4,\\s\\d4\\s\\d1,2:\\d2$", "dd MMMM yyyy HH:mm");
            put("^\\d1,2-\\d1,2-\\d4\\s\\d1,2:\\d2:\\d2$", "dd-MM-yyyy HH:mm:ss");
            put("^\\d4-\\d1,2-\\d1,2\\s\\d1,2:\\d2:\\d2$", "yyyy-MM-dd HH:mm:ss");
            put("^\\d1,2/\\d1,2/\\d4\\s\\d1,2:\\d2:\\d2$", "MM/dd/yyyy HH:mm:ss");
            put("^\\d4/\\d1,2/\\d1,2\\s\\d1,2:\\d2:\\d2$", "yyyy/MM/dd HH:mm:ss");
            put("^\\d1,2\\s[a-z]3\\s\\d4\\s\\d1,2:\\d2:\\d2$", "dd MMM yyyy HH:mm:ss");
            put("^\\d1,2\\s[a-z]4,\\s\\d4\\s\\d1,2:\\d2:\\d2$", "dd MMMM yyyy HH:mm:ss");
            put("^\\d4-\\d1,2-\\d1,2T\\d1,2:\\d2:\\d2\\.\\d2[-+]\\d2:\\d2$", "yyyy-MM-dd'T'HH:mm:ss.SSS");
        
    ;

    /**
     * To Determine the pattern by the string date value
     * 
     * @param dateString
     * @return The matching SimpleDateFormat pattern, or null if format is unknown.
     */
    public static String determineDateFormat(String dateString) 
        for (String regexp : DATE_FORMAT_REGEXPS.keySet()) 
            if (dateString.matches(regexp) || dateString.toLowerCase().matches(regexp)) 
                return DATE_FORMAT_REGEXPS.get(regexp);
            
        
        return null;
    

    public static void main(String[] args) 
        parse("2011-09-27T07:04:21.97-05:00"); //here is your value
        parse("20110917");
        parse("01/02/2018");
        parse("02-01-2018 06:07:59");
        parse("02 January 2018");
    

    public static void parse(String value) 
        if (value != null) 
            String format = determineDateFormat(value);
            if (format != null) 
                SimpleDateFormat sdf = new SimpleDateFormat(format);
                try 
                    Date date = sdf.parse(value);
                    System.out.println(String.format("Format : %s | Value : %s | Parsed Date : %s", value, date, format));
                 catch (ParseException e) 
                    // Failed the execution
                
            
        
    

类的控制台输出:

Format : 2011-09-27T07:04:21.97-05:00 | Value : Tue Sep 27 07:04:21 LINT 2011 | Parsed Date : yyyy-MM-dd'T'HH:mm:ss.SSS
Format : 20110917 | Value : Sat Sep 17 00:00:00 LINT 2011 | Parsed Date : yyyyMMdd
Format : 01/02/2018 | Value : Tue Jan 02 00:00:00 LINT 2018 | Parsed Date : MM/dd/yyyy
Format : 02-01-2018 06:07:59 | Value : Tue Jan 02 06:07:59 LINT 2018 | Parsed Date : dd-MM-yyyy HH:mm:ss
Format : 02 January 2018 | Value : Tue Jan 02 00:00:00 LINT 2018 | Parsed Date : dd MMMM yyyy

也许我在这里错过了一些日期时间模式,但为此应该在地图中添加正确的正则表达式模式。

【讨论】:

请不要教年轻人使用早已过时且臭名昭著的SimpleDateFormat类。至少不是第一选择。而且不是没有任何保留。今天我们在java.time, the modern Java date and time API, 和它的DateTimeFormatter 中做得更好。否则,这是一个创造性的解决方案。 这个例子不是要展示SimpleDateFormat是如何工作的,但是看看它是关于获取日期模式的问题,我只是用SimpleDateFormat来展示它实际上得到正确的模式,在得到正确的模式使用任何你想要的。 还有Don’t be “Clever”: The Double Curly Braces Anti Pattern 我想是否使用“双花括号反模式”将是一个单独的主题。 显然,您完全有权发表自己的意见。我的观点是,当您发布包含两种不良做法的答案而没有提及它们是不良做法时,您很可能会导致读者误入歧途而不是帮助他们。【参考方案9】:

java.time 及其预定义的格式化程序

我们不能只对任何日期时间格式执行此操作。它们有数千个,我们无法全部了解(明天有人会发明一个新的),有些看起来非常相似,我们不知道我们有哪一个。

我建议您在大多数情况下都需要解析字符串,但您不需要知道这样做的格式模式。在很多情况下,包括您问题中的示例 2011-09-27T07:04:21.97-05:00,我们不需要指定模式(您的字符串匹配 DateTimeFormatter.ISO_OFFSET_DATE_TIME)。

自从 Java 8 于 2014 年问世(即使仍在使用 Java 6 或 7),请使用现代 Java 日期和时间 API java.time 进行日期和时间工作。

我正在为我们想要满足的格式定义一组格式化程序。请替换您自己的设置。

private static final DateTimeFormatter[] formatters = 
        DateTimeFormatter.ISO_OFFSET_DATE_TIME,
        DateTimeFormatter.RFC_1123_DATE_TIME,
        new DateTimeFormatterBuilder().append(DateTimeFormatter.ISO_LOCAL_DATE)
                .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
                .toFormatter(),
        DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG).withLocale(Locale.US),
        DateTimeFormatter.ofPattern("MM/dd/uuuu HH:mm")
                .withZone(ZoneId.of("America/Los_Angeles"))
;

以下方法依次尝试格式化程序,直到一个工作:

private static OffsetDateTime parse(String dateTimeString) 
    for (DateTimeFormatter formatter : formatters) 
        try 
            return ZonedDateTime.parse(dateTimeString, formatter)
                    .toOffsetDateTime();
         catch (DateTimeParseException dtpe) 
            // Ignore, try next formatter
        
    
    throw new IllegalArgumentException("String " + dateTimeString + " could not be parsed");
 

让我们尝试一些不同的字符串:

    String[] dateTimeStrings = 
            "2011-09-27T07:04:21.97-05:00",
            "20110917",
            "2012-07-04",
            "12/27/2014 23:45",
            "Mon, 12 Nov 2018 01:32:10 GMT",
            "July 29, 2015 at 10:19:36 AM EDT",
    ;
    
    for (String dts : dateTimeStrings) 
        try 
            System.out.format("%32s -> %s%n", dts, parse(dts));
         catch (IllegalArgumentException iae) 
            System.out.format("%32s -> %s%n", dts, iae);
        
    

输出是:

    2011-09-27T07:04:21.97-05:00 -> 2011-09-27T07:04:21.970-05:00
                        20110917 -> java.lang.IllegalArgumentException: String 20110917 could not be parsed
                      2012-07-04 -> 2012-07-04T00:00Z
                12/27/2014 23:45 -> 2014-12-27T23:45-08:00
   Mon, 12 Nov 2018 01:32:10 GMT -> 2018-11-12T01:32:10Z
July 29, 2015 at 10:19:36 AM EDT -> 2015-07-29T10:19:36-04:00

其他选项

以多种格式解析日期和时间的技术包括:

试一试字符串以确定其格式,并在此基础上使用适当的格式化程序。如果您只有几种格式,它是最合适的,尽管 Vinit Solanki 的回答显示了相当多格式的详细版本。 在格式模式字符串中使用可选部分。例如,[uuuu][uu] 将解析四位数或两位数年份(2021 年或仅 21 年)。 依次尝试几个格式化程序,如我上面的代码所示。如果您确实需要了解模式,请使用模式数组而不是格式化程序数组。 要求字符串的供应商也提供格式模式字符串。不过,这并不总是像听起来那么简单。

谨防歧义。经典的例子是MM-dd-yyyydd-MM-yyyy这两种格式。如果我们得到一串03-09-2020,则无法判断它是指 3 月 9 日还是 9 月 3 日。更糟糕的是,02-05-07 可能是yy-MM-dddd-MM-yyMM-dd-yy 甚至更多可能性。因此,请确保您没有包含两个(或更多)可能将相同字符串解析为不同结果的格式化程序。

链接

Oracle tutorial: Date Time 解释如何使用 java.time。 A fine answer by Arvind Kumar Avinash 展示了使用格式模式字符串中的可选部分来解析不同的格式。

【讨论】:

【参考方案10】:
HH:mm:ss.SSS => ([0-2]1,[0-9]1,)(:)([0-5]1,[0-9]1,)(:)([0-5]1,[0-9]1,)(.)([0-9]1,3)

yyyy-mm-dd => ([0-9]4)(-)([0-1]1,[0-9]1,)(-)([0-3]1,[0-9]1,)

【讨论】:

以上是关于如何在java中获取给定的日期字符串格式(模式)?的主要内容,如果未能解决你的问题,请参考以下文章

如何以给定格式从 dijit.form.DateTextBox 获取日期?

java - 如何从Java中存储日期的给定字符串字段中减去X天? [复制]

java 用于验证给定字符串中的日期格式的Java Annotation

java中如何将字符串转换成日期型

在JAVA中获取日期和今天之间的月数[重复]

给定正则表达式模式的示例日期时间格式