【问题标题】:How to convert this string "Mon Jan 01 00:00:00 AEDT 1990" into "1990101"? [duplicate]如何将此字符串“Mon Jan 01 00:00:00 AEDT 1990”转换为“1990101”? [复制]
【发布时间】:2019-10-15 15:37:10
【问题描述】:

我有一个字符串“Mon Jan 01 00:00:00 AEDT 1990”,我需要将其转换为“yyyyMMdd”格式,因此在本例中为“19900101”。

我认为可以使用正则表达式来做到这一点,这样我就可以从字符串中提取年份、月份(但需要将 Jan 转换为 01 等)和日期,但我并不精通正则表达式。有人有什么想法吗?

【问题讨论】:

  • 尝试使用SimpleDateFormat
  • 这行不通,因为他使用的是自定义日期格式。
  • @Matthew 我给出了一个输出DAY : 19900101的代码示例
  • 我明白了,不知道它适用于自定义格式,干得好!
  • @Ole VV 我不推荐使用它或建议将其作为解决方案,我只是解释说我不知道​​这是可能的,因为我对此没有足够的了解,然后继续说“干得好”表示他的解决方案比我的好,就是这样。

标签: java regex string date parsing


【解决方案1】:

tl;博士

Regex 太过分了。

这是一个使用 Java 内置的 java.time 类的单线解决方案。

ZonedDateTime                            // Represent a moment as seen through the wall-clock time used by the people of a certain region (a time zone).
.parse(                                  // Parse the input text.
    "Mon Jan 01 00:00:00 AEDT 1990" ,     
    DateTimeFormatter.ofPattern( 
        "EEE MMM dd HH:mm:ss z uuuu" ,   // Specify a custom formatting pattern to match our input.
        Locale.US                        // Specify a `Locale` for the human language to use in translating the name of month& day-of-week.
    )                                    // Returns a `DateTimeFormatter` object.
)                                        // Returns a `ZonedDateTime` object.
.toLocalDate()                           // Extract the date, without time-of-day and without time zone. 
.format(                                 // Generate text to represent the value of our `LocalDate` object.
    DateTimeFormatter.BASIC_ISO_DATE     // Use the predefined formatting pattern YYYYMMDD.
)                                        // Returns a String.

19900101

java.time

正则表达式对此有点过分了。

现代方法使用 java.time 类。

指定自定义格式模式以适合您的输入。

指定语言环境以方便翻译星期几和月份的名称。

ZonedDateTime

解析为ZonedDateTime,通过特定地区(时区)的人们使用的挂钟时间看到的时刻。

String input = "Mon Jan 01 00:00:00 AEDT 1990";
Locale locale = Locale.US;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "EEE MMM dd HH:mm:ss z uuuu" , locale );
ZonedDateTime zdt = ZonedDateTime.parse( input , f );

System.out.println( "zdt: " + zdt );

zdt: 1990-01-01T00:00+11:00[澳大利亚/悉尼]

顺便说一句,你的输入字符串是 terrible 格式。它使用了 2-4 个字符的伪时区,它们不是实际的时区,不是标准化的,也不是唯一的!另一个问题是取决于英语。而且很难解析。让发布您的数据的人了解 ISO 8601 标准的美妙之处,该标准是为将日期时间值交换为文本而创建的。

LocalDate

您只需要日期。所以提取一个LocalDate

LocalDate ld = zdt.toLocalDate() ;  // Extract only the date, leaving behind the time-of-day and the time zone.

您想要的输出格式已经在DateTimeFormatter 类中定义。日期的标准 ISO 8601 格式是 YYYY-MM-DD。它的一种变体被称为“基本”,这意味着它最大限度地减少了分隔符的使用:YYYYMMDD。

String output = ld.format( DateTimeFormatter.BASIC_ISO_DATE ) ;

19900101

【讨论】:

  • 很好的答案...这让我太丢脸了,但至少我从中得到了一些练习。将其添加为书签,因为它将来会派上用场,谢谢。
  • @Matthew 在这里也有一个有效的正则表达式示例很好。
  • 您的解决方案是否适用于任何自定义日期格式?如果不能,你能给我一个例子,说明正则表达式是更好的解决方案吗?我想为使用java.time 不可行以使我的答案不完全无用的场景进行实现:D
  • @BasilBourque 感谢您提供的信息丰富的答案。是的,输入字符串的格式很糟糕,但我们使用的 ERP 系统就是这样输出的。
  • @Matthew 对于多种格式,您可以采用两种方式之一。您可以定义DateTimeFormatter 对象的集合,每个对象都具有针对您预期格式之一的自定义格式模式。然后对于每个输入循环集合,尝试每个格式化程序。如果抛出异常,则尝试下一个。或者,您可以使用帮助类DateTimeFormatterBuilder 构建更灵活的格式化程序,它可以设置一些可选部分和一些默认部分。搜索 Stack Overflow 以了解更多信息,因为这已多次解决。看特别是。对于 Ole V.V. 的构建器示例
【解决方案2】:

检查这样的事情是否有帮助

//date string
String soTime = "Mon Jan 04 12:30:23 AEDT 1990";

//Format
SimpleDateFormat so = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");

SimpleDateFormat desiredFormat = new SimpleDateFormat("yyyyMMdd");
desiredFormat.setTimeZone(TimeZone.getTimeZone("Australia/Sydney"));

Date sodate = so.parse(soTime);
System.out.println("DAY : " + desiredFormat.format(sodate));

Parse date with AEDT and AEST time zone in java

【讨论】:

  • 这些可怕的类在几年前被现代的 java.time 类所取代。 Sun、Oracle 和 JCP 社区都放弃了这些课程,采用了JSR 310。你也应该这样。
  • 请不要教年轻人使用早已过时且臭名昭著的麻烦SimpleDateFormat类。至少不是第一选择。而且不是没有任何保留。今天我们在java.time, the modern Java date and time API, 和它的DateTimeFormatter 中做得更好。
  • 指出谢谢。
【解决方案3】:

现在假设每个传递的字符串中的每个月和日名称都匹配枚举name 值之一(即“Mar” 匹配Month.MARCH 中字段name 的值,而"Marc""March" 没有)并且您提供给我们的示例字符串的格式是真正一致的,因为它在运行时不会更改,并且会始终保持<day-name> <month> <day> <time> <zone> <year> 其中年份始终是一个 4 位数字,下面的代码应该会给出你想要的答案:

主类

public static void main(String[] args) {

    String time = "Mon Jul 05 00:00:00 AEDT 1990";
    int result = CustomDateFormat.parseToInt(time);
    System.out.println("Parsed in format [yyyyMMdd]: " + result);
}

CustomDateFormat 类

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CustomDateFormat {

    private static final Pattern STANDARD_PATTERN =
    Pattern.compile("^(?:[a-zA-Z]{3})\\s([a-zA-Z]{3})\\s([0-9]{2}).*([0-9]{4})");

    /*
     * This is just in case you want
     * the name of the day as well
     */
    public enum Day {

        MONDAY("Mon", "Monday"),
        TUESDAY("Tue", "Tuesday"),
        WEDNESDAY("Wed", "Wednesday"),
        THURSDAY("Thu", "Thursday"),
        FRIDAY("Fri", "Friday"),
        SATURDAY("Sat", "Saturday"),
        SUNDAY("Sun", "Sunday");

        final String shortName;
        final String fullName;

        Day(String name1, String name2) {
            this.shortName = name1;
            this.fullName = name2;
        }

        public static String getFullName(String alias) {
            for (Day d : Day.values()) {
                if (d.shortName.equals(alias))
                    return d.fullName;
            }
            return "";
        }
    }

    public enum Month {

        JANUARY("Jan", 1), FEBRUARY("Feb", 2),
        MARCH("Mar", 3), APRIL("Apr", 4),
        MAY("May", 5), JUNE("Jun", 6),
        JULY("Jul", 7), AUGUST("Aug", 8),
        SEPTEMBER("Sep", 9), OCTOBER("Oct", 10),
        NOVEMBER("Nov", 11), DECEMBER("Dec", 12);

        final String name;
        final int value;

        Month(String name, int value) {
            this.name = name;
            this.value = value;
        }

        public static int getMonth(String month) {
            for (Month m : Month.values()) {
                if (m.name.equals(month))
                    return m.value;
            }
            return 0;
        }
    }

    public static int parseToInt(String date) {

        System.out.println("Parsing date: " + date);
        Matcher matcher = STANDARD_PATTERN.matcher(date);

        if (matcher.find() && matcher.groupCount() == 3)
        {
            int month = Month.getMonth(matcher.group(1));
            int day = Integer.valueOf(matcher.group(2));
            int year = Integer.valueOf(matcher.group(3));

            if (day == 0 || month == 0) {
                throw new IllegalStateException("Unable to parse day or month from date " + date);
            }
            else return Integer.valueOf(year + "0" + month + "0" + day);
        }
        else throw new IllegalStateException("Unable to parse date " + date);
    }
}

输出

Parsing date: Mon Jul 05 00:00:00 AEDT 1990
Parsed in format [yyyyMMdd]: 19900705

让我知道这是否满足您的要求以及是否需要满足任何其他条件或考虑特殊情况场景。这是一个相当简单的实现,因此无需花时间就可以根据更具体的需求进行调整。

编辑:修复一些实现错误,将示例字符串更改为自定义字符串并删除多余的输出行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-07
    • 2020-07-17
    • 1970-01-01
    • 1970-01-01
    • 2021-03-30
    • 1970-01-01
    • 2015-09-03
    相关资源
    最近更新 更多