У меня есть строка «Mon Jan 01 00:00:00 AEDT 1990», и мне нужно преобразовать ее в формат «yyyyMMdd», поэтому в этом случае это будет «19900101».
Я думаю, что это можно сделать с помощью регулярных выражений, чтобы я мог вытащить год, месяц (но мне нужно было бы преобразовать январь в 01 и т. д.) и день из строки, но я плохо разбираюсь в регулярных выражениях. У кого-нибудь есть идеи?
Это не сработает, поскольку он использует собственный формат даты.
@Matthew Я дал пример кода, который выводит DAY : 19900101
Я вижу, не знал, что это работает с пользовательскими форматами, хорошая работа!
@ Мэтью Я позволю себе не согласиться, извините, заставить SimpleDateFormat
работать иногда бывает непросто, но советовать это как решение - плохой совет. Этот класс, как известно, доставляет много хлопот и, к счастью, давно устарел. Мы никогда не должны использовать его больше.
@Ole VV Я не рекомендовал его использование или советовал как решение, я просто объяснял, что не знал, что это возможно, потому что у меня недостаточно знаний об этом, а затем продолжил говорить "хорошая работа", чтобы сигнализировать о том, что его решение был лучше моего, вот и все.
Джон-Майкл, ваша строка Mon Jan 01 00:00:00 AEDT 1990
очень похожа на строку, возвращенную из Date.toString
. Поэтому я добавил исходный вопрос, а также предоставил новый ответ для вас здесь (новый ответ не распространяется на форматирование в 19900101
, но это было рассмотрено в ответе Бэзила Бурка, а также рассмотрено в первом исходном вопросе).
Теперь предположим, что имена каждого месяца и дня в каждой переданной строке соответствуют одному из значений 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
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 Хорошо иметь здесь и рабочий пример регулярного выражения.
Ваше решение работает для любого пользовательского формата даты? Если нет, можете ли вы привести пример сценария, в котором регулярное выражение было бы лучшим решением? Я хотел бы реализовать сценарии, в которых использование java.time
невозможно, чтобы мой ответ не был полностью бесполезным: D
@BasilBourque Спасибо за этот информативный ответ. Да, входная строка имеет ужасный формат, но система ERP, которую мы используем, выводит ее именно так.
@Matthew Для нескольких форматов вы можете пойти одним из двух способов. Вы можете определить набор объектов DateTimeFormatter
, каждый из которых имеет собственный шаблон форматирования для одного из ожидаемых форматов. Затем для каждого ввода вы зацикливаете коллекцию, пробуя каждый форматировщик. Если возникает исключение, вы пытаетесь выполнить следующее. В качестве альтернативы вы можете создать более гибкий модуль форматирования, используя вспомогательный класс DateTimeFormatterBuilder
, который может устанавливать некоторые необязательные части и некоторые части по умолчанию. Найдите Stack Overflow, чтобы узнать больше, так как это уже обсуждалось много раз. Смотри спец. для примеров строителей Оле В.В.
@ John-Michael, я предлагаю вам подать заявку на выпуск у поставщика вашей ERP-системы. После того, как они узнали об ISO 8601, им может быть тривиально (возможно, 1 строка кода) предоставить строку, совместимую с ISO 8601, в качестве альтернативы их текущему выводу. Классы Java.время по умолчанию используют стандартные форматы ISO 8601 при анализе/генерации текста, поэтому вы просто вызываете parse
или toString
без каких-либо DateTimeFormatter
. См. комментарий Оле В.В. на ваш вопрос по ссылке для получения дополнительной информации.
Проверьте, помогает ли что-то подобное
//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. Так и вы.
Пожалуйста, не учите молодежь использовать давно устаревший и заведомо проблемный класс SimpleDateFormat
. По крайней мере, не в качестве первого варианта. И не без оговорок. Сегодня у нас намного лучше в java.time
, современный API даты и времени Java, и его DateTimeFormatter
.
Точка отмечена Спасибо.
Попробуйте использовать
SimpleDateFormat