2016-08-31 2 views
1

Следующий код для now() выполняется дважды для объекта. Однажды обозначить его создание и другое время для обозначения, когда оно было записано в базу данных.DateFormat или Calender.getInstance иногда возвращает случайные значения

В контролируемом тесте мне удалось достоверно воспроизвести ошибку, где даты сильно различаются между собой. Некоторые даты, похоже, имеют правильную дату, но находятся в 00:00:00 или почти 00:00:00.

Другие, по-видимому, относительно неактивны на несколько часов, варьируя от 1 часа до 16 или даже недель. У меня также были времена в будущем. Calendar.getInstance.getTime() должен быть эквивалентен System.getCurrentTimeMillis(), при этом последний возвращает время в будущем некоторое время.

Я ничего не нашел и буду дальше изучать этот вопрос и сообщать о своих выводах здесь.

private static DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); 

public static String calendarToDb(Calendar cal) { 
    if (cal == null) { 
     return null; 
    } 
    return simpleDateFormat.format(cal.getTime()); 
} 

public static String now() { 
    return calendarToDb(Calendar.getInstance()); 
} 

Ниже приведена соответствующая часть журнала с андроид-монитора. Это настоящее устройство, а не эмулятор. M для MessageManager и Р для ContentProvider

08-30 18:07:17.267 M: main    starttime = 2016-01-01T00:07:00+0100\ 
08-30 18:07:17.306 P: AsyncQueryWorker CreateTime = 2016-08-30T18:07:17+0200\ 
08-30 18:07:18.326 M: main    starttime = 2016-01-01T00:00:00+0200\ 
08-30 18:07:18.371 P: AsyncQueryWorker CreateTime = 2016-08-30T18:07:18+0200\ 
08-30 18:07:19.898 M: main    starttime = 2016-08-30T18:07:19+0200\ 
08-30 18:07:19.920 P: AsyncQueryWorker CreateTime = 2016-08-30T00:00:00+0100\ 

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

+0

странно ... Предполагаю, что вы используете несколько потоков. Рассматривали ли вы использование новой даты api java8 или с помощью 'JodaTime'? – abbath

+0

Да, я использую разные потоки (основной и AsyncQueryWorkerThread). Я не думаю, что java8 доступен для более ранних афинов уровня api? – HopefullyHelpful

+0

Дело в том, что большую часть времени он работает, он просто имеет смысл иногда возвращать случайное значение или сбросить даты/время – HopefullyHelpful

ответ

3

Проблема, кажется, лежит, скорее всего, в статических

static DateFormat simpleDateFormat 

Как объяснено здесь: Why is Java's SimpleDateFormat not thread-safe?

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

Решение должно возвращать новые экземпляры каждый раз.

1

Избегайте унаследованных даты и времени занятия

The Answer by HopefullyHelpful является правильным, и должны быть приняты. Вероятно, вы видите ошибки из-за отсутствия безопасности потоков в старых классах времени. Это один из причин, чтобы избежать этих неприятных старых устаревших классов времени.

Вместо этого вы должны использовать классы java.time. В классах java.time реализована защита от потоков.

ISO 8601

Ваши входные строки случается соответствовать стандарту ISO 8601 для форматов даты и времени.

В классах java.time по умолчанию используются форматы ISO 8601 при разборе/генерации строк. Поэтому вам не нужно указывать шаблон форматирования, но для ошибки в текущей реализации Java 8. В настоящее время отсутствие двоеточия в смещении-от-UTC заставляет по умолчанию игнорировать синтаксический анализ. Должно быть исправлено в Java 9. В то время как в Java 8 укажите шаблон с DateTimeFormatter и DateTimeFormatterBuilder.

String input = "2016-08-30T18:07:17+0200"; 

DateTimeFormatterBuilder fb = new DateTimeFormatterBuilder().append (DateTimeFormatter.ISO_LOCAL_DATE_TIME).appendOffset ("+HHMM" , "Z"); 
DateTimeFormatter f = fb.toFormatter(); 

OffsetDateTime

ваших входных строк указывают на смещение, из-UTC, но не полный часовой пояс. Итак, мы анализируем как OffsetDateTime объектов.

В Java 9, а затем, анализировать непосредственно:

OffsetDateTime odt = OffsetDateTime.parse (input); 

В Java 8, используйте DateTimeFormatter объект, построенный выше.

OffsetDateTime odt = OffsetDateTime.parse (input , f); 

Дамп для консоли.

System.out.println ("input: " + input + " | odt: " + odt); 

вход: 2016-08-30T18: 07: 17 + 0200 | odt: 2016-08-30T18: 07: 17 + 02: 00

 Смежные вопросы

  • Нет связанных вопросов^_^