Форматирование даты и времени в соответствии с языком и предпочтениями пользователя с секундами

Я пытаюсь получить отформатированную строку даты (год, месяц, дата) и время (часы, минуты, секунды) в соответствии с настройками пользователя. Этот пост в группе разработчиков Android для разработчиков описывает точную проблему, с которой я столкнулся, но никто не помог этому человеку решить ее. Я подведу итог:

В Android есть эти классы, которые пытаются выполнить вышеизложенное, но ни один из них не использует ни пользовательские настройки, ни отображает секунды.

  1. java.text.DateFormat
    Не использует настройки, установленные в приложении "Настройки"

  2. android.text.format.DateFormat
    Получает java.text.DateFormat объект, который форматирует вывод правильно, используя getDateFormat() а также getTimeFormat(), но getTimeFormat() не включает в себя секунды.

  3. 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

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 );
Другие вопросы по тегам