Как преобразовать эту строку «Mon Jan 01 00:00:00 AEDT 1990» в «1990101»?

У меня есть строка «Mon Jan 01 00:00:00 AEDT 1990», и мне нужно преобразовать ее в формат «yyyyMMdd», поэтому в этом случае это будет «19900101».

Я думаю, что это можно сделать с помощью регулярных выражений, чтобы я мог вытащить год, месяц (но мне нужно было бы преобразовать январь в 01 и т. д.) и день из строки, но я плохо разбираюсь в регулярных выражениях. У кого-нибудь есть идеи?

Попробуйте использовать SimpleDateFormat

Albatross 30.05.2019 03:51

Это не сработает, поскольку он использует собственный формат даты.

Matthew 30.05.2019 03:58

@Matthew Я дал пример кода, который выводит DAY : 19900101

Albatross 30.05.2019 04:16

Я вижу, не знал, что это работает с пользовательскими форматами, хорошая работа!

Matthew 30.05.2019 04:36

@ Мэтью Я позволю себе не согласиться, извините, заставить SimpleDateFormat работать иногда бывает непросто, но советовать это как решение - плохой совет. Этот класс, как известно, доставляет много хлопот и, к счастью, давно устарел. Мы никогда не должны использовать его больше.

Ole V.V. 30.05.2019 10:26

@Ole VV Я не рекомендовал его использование или советовал как решение, я просто объяснял, что не знал, что это возможно, потому что у меня недостаточно знаний об этом, а затем продолжил говорить "хорошая работа", чтобы сигнализировать о том, что его решение был лучше моего, вот и все.

Matthew 30.05.2019 10:29

Джон-Майкл, ваша строка Mon Jan 01 00:00:00 AEDT 1990 очень похожа на строку, возвращенную из Date.toString. Поэтому я добавил исходный вопрос, а также предоставил новый ответ для вас здесь (новый ответ не распространяется на форматирование в 19900101, но это было рассмотрено в ответе Бэзила Бурка, а также рассмотрено в первом исходном вопросе).

Ole V.V. 30.05.2019 10:57
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
7
355
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Теперь предположим, что имена каждого месяца и дня в каждой переданной строке соответствуют одному из значений enum name (т. е. "Мар" соответствует значению поля name в Month.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

Дайте мне знать, соответствует ли это вашим требованиям и необходимо ли выполнить какие-либо другие условия или рассмотреть сценарии особый случай. Это довольно простая реализация, поэтому ее настройка для более конкретных нужд не займет много времени.

Обновлено: Исправьте некоторые ошибки реализации, измените образец строки на пользовательскую и удалите лишнюю строку вывода.

Ответ принят как подходящий

тл;др

регулярное выражение является излишним.

Вот однострочное решение, использующее классы Java.время, встроенные в Java.

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.время

Regex для этого является излишним.

Современный подход использует классы Java.время.

Укажите пользовательский шаблон форматирования, соответствующий вашему вводу.

Укажите языковой стандарт для облегчения перевода названия дня недели и названия месяца.

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[Australia/Sydney]

Кстати, ваша входная строка имеет формат ужасный. Он использует псевдозоны из 2-4 символов, которые не являются фактическими часовыми поясами, не стандартизированы и не уникальны! Другая проблема зависит от английского языка. И сложно разобрать. Расскажите людям, публикующим ваши данные, о красоте стандарта ИСО 8601, созданного для обмена значениями даты и времени в виде текста.

LocalDate

Вам нужна только дата. Так что извлеките LocalDate.

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

Желаемый формат вывода уже определен в классе DateTimeFormatter. Стандартный формат даты ИСО 8601 — ГГГГ-ММ-ДД. Вариант этого известен как «Базовый», что означает, что он сводит к минимуму использование разделителей: ГГГГММДД.

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

19900101

Отличный ответ ... это слишком стыдно для меня, но, по крайней мере, я получил от этого некоторую практику. Беру в закладки, вдруг пригодится в будущем, спасибо.

Matthew 30.05.2019 04:34

@Matthew Хорошо иметь здесь и рабочий пример регулярного выражения.

Basil Bourque 30.05.2019 04:36

Ваше решение работает для любого пользовательского формата даты? Если нет, можете ли вы привести пример сценария, в котором регулярное выражение было бы лучшим решением? Я хотел бы реализовать сценарии, в которых использование java.time невозможно, чтобы мой ответ не был полностью бесполезным: D

Matthew 30.05.2019 04:42

@BasilBourque Спасибо за этот информативный ответ. Да, входная строка имеет ужасный формат, но система ERP, которую мы используем, выводит ее именно так.

John-Michael 30.05.2019 04:42

@Matthew Для нескольких форматов вы можете пойти одним из двух способов. Вы можете определить набор объектов DateTimeFormatter, каждый из которых имеет собственный шаблон форматирования для одного из ожидаемых форматов. Затем для каждого ввода вы зацикливаете коллекцию, пробуя каждый форматировщик. Если возникает исключение, вы пытаетесь выполнить следующее. В качестве альтернативы вы можете создать более гибкий модуль форматирования, используя вспомогательный класс DateTimeFormatterBuilder, который может устанавливать некоторые необязательные части и некоторые части по умолчанию. Найдите Stack Overflow, чтобы узнать больше, так как это уже обсуждалось много раз. Смотри спец. для примеров строителей Оле В.В.

Basil Bourque 30.05.2019 05:15

@ John-Michael, я предлагаю вам подать заявку на выпуск у поставщика вашей ERP-системы. После того, как они узнали об ISO 8601, им может быть тривиально (возможно, 1 строка кода) предоставить строку, совместимую с ISO 8601, в качестве альтернативы их текущему выводу. Классы Java.время по умолчанию используют стандартные форматы ISO 8601 при анализе/генерации текста, поэтому вы просто вызываете parse или toString без каких-либо DateTimeFormatter. См. комментарий Оле В.В. на ваш вопрос по ссылке для получения дополнительной информации.

Basil Bourque 30.05.2019 14:00

Проверьте, помогает ли что-то подобное

//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));

Дата анализа с часовым поясом AEDT и AEST в java

Эти ужасные классы были вытеснены много лет назад современными классами Java.время. Sun, Oracle и сообщество JCP отказались от этих классов с принятием JSR 310. Так и вы.

Basil Bourque 30.05.2019 04:25

Пожалуйста, не учите молодежь использовать давно устаревший и заведомо проблемный класс SimpleDateFormat. По крайней мере, не в качестве первого варианта. И не без оговорок. Сегодня у нас намного лучше в java.time, современный API даты и времени Java, и его DateTimeFormatter.

Ole V.V. 30.05.2019 10:08

Точка отмечена Спасибо.

Albatross 30.05.2019 20:15

Другие вопросы по теме