часовой пояс
Вопрос и другие ответы игнорируют критическую проблему часового пояса. В этой входной строке отсутствует часовой пояс или offset-from-UTC . Таким образом, эта строка будет проанализирована, если предположить, что она представляет дату-время в текущем часовом поясе JVM по умолчанию. Опасно, что (а) это предположение может быть ложным, и (б) это значение по умолчанию может измениться в любой момент, даже в течение времени выполнения.
Locale
Вопрос и другие ответы игнорируют еще одну важную проблему: Locale
. Locale определяет человеческий язык, используемый для перевода названия дня и названия месяца из входной строки во время синтаксического анализа (и генерации).
Если не указано, для перевода будет использоваться текущий язык по умолчанию JVM. Как и в случае с часовым поясом, языковой стандарт JVM по умолчанию может измениться в любой момент, даже во время времени выполнения.
Лучше указать желаемый / ожидаемый язык.
java.time
В Вопросе и других Ответах используются старые классы даты и времени, которые оказались плохо продуманными и проблемными. Java 8 и более поздние версии имеют встроенную инфраструктуру java.time , классы которой вытесняют старые.
Ваш метод для анализа строки при генерации новой строки должен быть разбит на два метода. Один метод должен анализировать, чтобы получить объекты даты и времени. Второй должен принимать объекты даты и времени и генерировать желаемую строку вывода. Тогда каждый может быть использован отдельно. И этот подход уводит нас от мысли о строках как о значениях даты и времени. Строки представляют собой текстовые представления значений даты и времени. Ваша бизнес-логика должна фокусироваться на манипулировании этими значениями даты и времени как на объектах, а не на строках.
Синтаксический
private ZonedDateTime parseLengthyString ( String input , ZoneId zoneId , Locale locale ) {
// FIXME: Check for nulls.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "EEE hh:mma MMM d, uuuu" );
formatter = formatter.withZone ( zoneId );
formatter = formatter.withLocale ( locale );
ZonedDateTime zdt = null;
try {
zdt = ZonedDateTime.parse ( input , formatter );
} catch ( DateTimeParseException e ) {
// FIXME: handle exeption.
System.out.println ( "ERROR - e: " + e );
}
return zdt; // FIXME: Check for null.
}
Генерация
Учитывая ZonedDateTime
в руке из описанного выше метода, мы можем сгенерировать текстовое представление его значения даты и времени, используя указанный языковой стандарт для перевода названия дня и названия месяца.
Чтобы определить, является ли дата-время сегодняшним или вчерашним, нам важна только часть даты без времени дня. Для этого мы можем использовать класс LocalDate
в java.time.
private String generateLengthyString ( ZonedDateTime zdt , Locale locale ) {
// FIXME: Check for nulls.
// Compare the date-only value of incoming date-time to date-only of today and yesterday.
LocalDate localDateIncoming = zdt.toLocalDate ();
Instant instant = Instant.now ();
ZonedDateTime now = ZonedDateTime.now ( zdt.getZone () ); // Get current date-time in same zone as incoming ZonedDateTime.
LocalDate localDateToday = now.toLocalDate ();
LocalDate localDateYesterday = localDateToday.minusDays ( 1 );
DateTimeFormatter formatter = null;
if ( localDateIncoming.isEqual ( localDateToday ) ) {
formatter = DateTimeFormatter.ofPattern ( "'Today' hh:mma" , locale ); // FIXME: Localize "Today".
} else if ( localDateIncoming.isEqual ( localDateYesterday ) ) {
formatter = DateTimeFormatter.ofPattern ( "'Yesterday' hh:mma" , locale ); // FIXME: Localize "Yesterday".
} else {
formatter = DateTimeFormatter.ofPattern ( "EEE hh:mma MMM d, uuuu" , locale );
}
String output = zdt.format ( formatter );
return output; // FIXME: Check for null.
}
Пример * * тысяча сорок-четырь
Используйте эти два метода.
Произвольно выбрав часовой пояс America/New_York
, поскольку Вопрос не уточняет.
String input = "Sat 11:23AM Feb 6, 2016";
ZoneId zoneId = ZoneId.of ( "America/New_York" );
Locale locale = Locale.US;
ZonedDateTime zdt = this.parseLengthyString ( input , zoneId , locale );
String output = this.generateLengthyString ( zdt , locale );
Кстати, вы можете попросить java.time автоматически форматировать выходную строку в соответствии с культурными нормами локали вместо жесткого кодирования формата.
String outputPerLocale = zdt.format ( DateTimeFormatter.ofLocalizedDateTime ( FormatStyle.MEDIUM ) );
Дамп на консоль.
System.out.println ( "input: " + input + " | zdt: " + zdt + " | Instant: " + zdt.toInstant () + " | output: " | output + " + outputPerLocale: " + outputPerLocale );
вход: сб 11:23 6 февраля 2016 | дата: 2016-02-06T11: 23-05: 00 [Америка / Нью-Йорк] | Мгновенное действие: 2016-02-06T16: 23:00 | выходной: сегодня 11:23 | outputPerLocale: 6 февраля 2016 г. 11:23:00
Кстати, я предлагаю поставить ПРОБЕЛ перед AM
или PM
для удобства чтения.