Форматирование даты и времени в соответствии с языком и предпочтениями пользователя с секундами
Я пытаюсь получить отформатированную строку даты (год, месяц, дата) и время (часы, минуты, секунды) в соответствии с настройками пользователя. Этот пост в группе разработчиков Android для разработчиков описывает точную проблему, с которой я столкнулся, но никто не помог этому человеку решить ее. Я подведу итог:
В Android есть эти классы, которые пытаются выполнить вышеизложенное, но ни один из них не использует ни пользовательские настройки, ни отображает секунды.
java.text.DateFormat
Не использует настройки, установленные в приложении "Настройки"android.text.format.DateFormat
Получаетjava.text.DateFormat
объект, который форматирует вывод правильно, используяgetDateFormat()
а такжеgetTimeFormat()
, ноgetTimeFormat()
не включает в себя секунды.android.text.format.DateUtils
Не использует настройки, установленные для отображения даты в приложении "Настройки", и не позволяет отображать секунды.
Например, с настройками в настройках "ДД / ММ / ГГГГ" и 24-часовым форматом "=", запустите следующий код:
long timestamp=System.currentTimeMillis();
sometextview.setText(
java.text.format.DateFormat.getDateTimeInstance().format(new Date(timestamp))
+"\n"+
android.text.format.DateFormat.getDateFormat(this).format(new Date(timestamp))
+" "+
android.text.format.DateFormat.getTimeFormat(this).format(new Date(timestamp))
+"\n"+
android.text.format.DateUtils.formatDateTime(this,
timestamp,
DateUtils.FORMAT_SHOW_DATE|
DateUtils.FORMAT_SHOW_TIME|
DateUtils.FORMAT_SHOW_YEAR)
);
дает мне следующий вывод в textview:
Apr 27,2014 5:47:18 PM
27/04/2014 17:47
April 27,2014, 17:47
Ни один из них не дает желаемого результата, который будет выглядеть примерно так с использованием вышеупомянутых предпочтений:
27/04/2014 17:47:18
Я также посмотрел библиотеку https://github.com/dlew/joda-time-android, но, похоже, она не делает то, что мне нужно (поправьте меня, если я ошибаюсь).
TL; DR: Как вы форматируете дату / время в соответствии с предпочтениями пользователя с секундами на Android?
5 ответов
С помощью @I wish I could think of a good
Я предложил следующий код, который форматирует дату, используя локаль и пользовательские настройки:
public static String timeDateStringFromTimestamp(Context applicationContext,long timestamp){
String timeDate;
String androidDateTime=android.text.format.DateFormat.getDateFormat(applicationContext).format(new Date(timestamp))+" "+
android.text.format.DateFormat.getTimeFormat(applicationContext).format(new Date(timestamp));
String javaDateTime = DateFormat.getDateTimeInstance().format(new Date(timestamp));
String AmPm="";
if(!Character.isDigit(androidDateTime.charAt(androidDateTime.length()-1))) {
if(androidDateTime.contains(new SimpleDateFormat().getDateFormatSymbols().getAmPmStrings()[Calendar.AM])){
AmPm=" "+new SimpleDateFormat().getDateFormatSymbols().getAmPmStrings()[Calendar.AM];
}else{
AmPm=" "+new SimpleDateFormat().getDateFormatSymbols().getAmPmStrings()[Calendar.PM];
}
androidDateTime=androidDateTime.replace(AmPm, "");
}
if(!Character.isDigit(javaDateTime.charAt(javaDateTime.length()-1))){
javaDateTime=javaDateTime.replace(" "+new SimpleDateFormat().getDateFormatSymbols().getAmPmStrings()[Calendar.AM], "");
javaDateTime=javaDateTime.replace(" "+new SimpleDateFormat().getDateFormatSymbols().getAmPmStrings()[Calendar.PM], "");
}
javaDateTime=javaDateTime.substring(javaDateTime.length()-3);
timeDate=androidDateTime.concat(javaDateTime);
return timeDate.concat(AmPm);
}
Попробуй это:
long timestamp = System.currentTimeMillis();
DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(getApplicationContext());
DateFormat timeFormat = DateFormat.getTimeInstance();
String currentTimeString = dateFormat.format(timestamp) + " - " +
timeFormat.format(timestamp);
Почему бы не использовать гибридное решение
android.text.format.DateFormat.getDateFormat(this).format(new Date(timestamp));
а также
java.text.format.DateFormat.getDateTimeInstance().format(new Date(timestamp))
За getDateTimeInstance
сохранить его в виде строки и извлечь секунды, а затем просто добавить его к getDateFormat
Немного взломать, но это, кажется, работает:
Date date = ...;
String dateStr = DateFormat.getLongDateFormat(context).format(date);
String timeStr;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
String timeFormat = DateFormat.getBestDateTimePattern(Locale.getDefault(), DateFormat.is24HourFormat(context) ? "Hms" : "hmsa");
timeStr = new SimpleDateFormat(timeFormat, Locale.getDefault()).format(date);
}
else {
String timeFormat = DateFormat_getTimeFormatString(context).replace("mm", "mm:ss");
timeStr = new SimpleDateFormat(timeFormat, Locale.getDefault()).format(date);
}
return dateStr + " " + timeStr;
Он опирается на скрытую функцию в DateFormat, которую мы можем использовать с помощью отражения:
private static String DateFormat_getTimeFormatString(Context context) {
try {
final Method method = DateFormat.class.getDeclaredMethod("getTimeFormatString");
method.setAccessible(true);
return (String) method.invoke(context);
}
catch (Exception ignored) {
return "HH:mm";
}
}
С API 18 и далее вы можете использовать новый getBestDateTimePattern()
функция, которая нуждается только в списке данных, которые вы хотите отобразить, и возвращает шаблон наилучшего соответствия.
Если вы посмотрите в is24HourFormat()
Исходный код немного ненормальный (он проверяет, есть ли заглавная буква H в строке шаблона, которую предпочитает пользователь), поэтому, возможно, стоит сохранить его значение, а не вызывать его повторно, если вам нужно отобразить много дат.
Конечно, вы можете решить, какой формат вам нужен для даты, вызывая другие экземпляры или используя DateUtils.formatDateTime()
,
Одно предупреждение, хотя. Убедитесь, что вы используете контекст активности, чтобы запросить is24HourFormat()
, Прикладные контексты не подойдут.
ТЛ; др
ZonedDateTime.now( ZoneId.of( "America/Montreal" ) )
.format( DateTimeFormatter.ofPattern( "dd/MM/uuuu HH:mm:ss" ) )
23.01.2017 12:34:56
java.time
Добавьте проект ThreeTenABP (см. Ниже), чтобы получить доступ к современным классам даты и времени фреймворка java.time. Старые устаревшие классы даты и времени, как известно, хлопотны, сбивают с толку и имеют недостатки.
Часовой пояс имеет решающее значение при определении даты. В любой момент времени дата меняется по всему земному шару в зависимости от зоны. Например, через несколько минут после полуночи в Париже Франция - новый день, а в Монреале-Квебеке все еще "вчера".
Укажите правильное название часового пояса в формате continent/region
, такие как America/Montreal
, Africa/Casablanca
, или же Pacific/Auckland
, Никогда не используйте 3-4 буквенное сокращение, такое как EST
или же IST
поскольку они не являются истинными часовыми поясами, не стандартизированы и даже не уникальны (!).
ZoneId z = ZoneId.of( "America/Montreal" ); // Or ZoneId.systemDefault()
ZonedDateTime zdt = ZonedDateTime.now( z );
использование DateTimeFormatter
генерировать строку, представляющую значение этого ZonedDateTime
объект. Укажите пользовательский шаблон форматирования или вызовите toLocalized…
методы автоматической локализации пользователя на человеческий язык и культурные нормы.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu HH:mm:ss" ) ;
String output = zdt.format( f );
23.01.2017 12:34:56
О java.time
Инфраструктура java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые классы даты и времени, такие как java.util.Date
, Calendar
& SimpleDateFormat
,
Проект Joda-Time, находящийся сейчас в режиме обслуживания, рекомендует перейти на классы java.time.
Чтобы узнать больше, смотрите Oracle Tutorial. И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310.
Где взять классы java.time?
- Java SE 8, Java SE 9 и более поздние
- Встроенный.
- Часть стандартного Java API со встроенной реализацией.
- Java 9 добавляет некоторые незначительные функции и исправления.
- Java SE 6 и Java SE 7
- Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport.
- Android
- Проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше) специально для Android.
- Смотрите Как использовать ThreeTenABP….
Joda времени
Обновление: проект Joda-Time, находящийся сейчас в режиме обслуживания, рекомендует перейти на классы java.time.
Joda-Time легко форматирует значения даты и времени с учетом языка. Посмотрите на DateTimeFormat
учебный класс.
DateTimeFormatter formatter = DateTimeFormat.forStyle( "SM" );
DateTime dateTime = DateTime.now();
String output = formatter.print( dateTime );
Поиграйте с этой последовательностью из двух букв, чтобы получить желаемый формат. Первый символ - это стиль даты, а второй - стиль времени. Укажите символ 'S' для короткого стиля, 'M' для среднего, 'L' для длинного и 'F' для полного. Дата или время могут быть опущены, указав символ стиля '-'.
место действия
Locale
контролирует форматирование в соответствии с культурными нормами и контролирует язык, используемый для перевода названия дня, названия месяца и т. д.
Если вы не укажете языковой стандарт, текущий языковой стандарт по умолчанию JVM будет применен автоматически. Так как это значение по умолчанию может измениться в момент до или даже во время выполнения, я предлагаю вам указать желаемый / ожидаемый языковой стандарт. Если вы действительно хотите текущее значение по умолчанию, я предлагаю указать это также с вызовом Locale.getDefault
чтобы сделать ваш код самодокументированным.
formatter = formatter.withLocale( Locale.CANADA_FRENCH );