![]() |
Модераторы: LSD, AntonSaburov |
![]() ![]() ![]() |
|
arcsupport |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 725 Регистрация: 24.10.2008 Репутация: 1 Всего: 2 |
Существуют ли стандартные (встроенные в JRE) классы, объекты и методы, которые позволят рассчитать количество лет, месяцев, недель и дней между двумя датами по грегорианскому календарю?
По юлианскому календарю? |
|||
|
||||
jk1 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 1168 Регистрация: 17.10.2008 Где: Санкт-Петербург Репутация: 40 Всего: 75 |
Это как бы основа
А конкретный тип календаря определяется конкретным наследником java.util.Calendar. Например там есть GregorianCalendar. -------------------- Opinions are like assholes — everybody has one |
|||
|
||||
arcsupport |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 725 Регистрация: 24.10.2008 Репутация: 1 Всего: 2 |
jk1, меня больше интересует не общее количество дней, а количество лет, месяцев, недель и дней между двумя датами.
|
|||
|
||||
Stolzen |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1041 Регистрация: 17.10.2005 Репутация: 23 Всего: 48 |
arcsupport, можно примерно так
Оно? Добавлено через 5 минут и 2 секунды Года не добавлял, т.к. они могут быть високосные и невисокосные. Если это не важно, то в массив MILILIS можно добавить на первое место еще одну константу MILLIS_PER_YEAR = 355 * MILLIS_PER_DAY; и в MessageFormat.format("{0} days, {1} hours, {2} minutes", res); добавить {0} years |
||||
|
|||||
jk1 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 1168 Регистрация: 17.10.2008 Где: Санкт-Петербург Репутация: 40 Всего: 75 |
Не надо изобретать велосипедов. Класс TimeUnit, о котором я говорил выше, умеет выполнять преобразования единиц времени. В данном случае это будут преобразования милисекунд в минуты, часы, дни. -------------------- Opinions are like assholes — everybody has one |
|||
|
||||
Stolzen |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1041 Регистрация: 17.10.2005 Репутация: 23 Всего: 48 |
Преобразование он делать умеет, а вот делить с остатком - нет
|
|||
|
||||
jk1 |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 1168 Регистрация: 17.10.2008 Где: Санкт-Петербург Репутация: 40 Всего: 75 |
Умеет
дает в результате 1 -------------------- Opinions are like assholes — everybody has one |
||||
|
|||||
Stolzen |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1041 Регистрация: 17.10.2005 Репутация: 23 Всего: 48 |
А остаток?
|
|||
|
||||
jk1 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 1168 Регистрация: 17.10.2008 Где: Санкт-Петербург Репутация: 40 Всего: 75 |
Вуаля
-------------------- Opinions are like assholes — everybody has one |
|||
|
||||
Mirkes |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 586 Регистрация: 18.8.2011 Где: Красноярск Репутация: 7 Всего: 17 |
По моему умудренные советчики не поняли вопроса. Вопрос в исчислении стажа того или иного вида. То есть следует указать сколько лет, месяцев и дней прошло от одной даты до другой.
Нельзя говорить 100 дней, нужно сказать три месяца и ? дней. С этого момента начинаются неприятности при подсчете стажей, поскольку разные месяцы содержат разное число дней. Далее вопрос о том, какая точность нужна. Ниже пример для грубого подсчета без делений, а средствами стандартных библиотек. Еще ниже (по тексту) пример точного подсчета. Текст не оптимизирован. Если задача регулярная, то стоит написать отдельную функцию и почистить код.
пример вывода 1257 вариант jk1 - просто число дней. 11 days 5 month 3 years грубый расчет. 9 days 5 month 3 years точный расчет Забавно, но куда-то потерялось два дня. Я думал что разность будет в один день. -------------------- Mirkes |
|||
|
||||
arcsupport |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 725 Регистрация: 24.10.2008 Репутация: 1 Всего: 2 |
Mirkes, спасибо.
|
|||
|
||||
Dummy |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 263 Регистрация: 21.5.2007 Репутация: 9 Всего: 19 |
Mirkes, в вашей реализации я вижу пару моментов, с которыми хочется поспорить.
На моей машине и с моим самопальным тестом (не претендующим на особую прецизионность), скорость вычисления увеличивается раза в полтора-два. Это сообщение отредактировал(а) Dummy - 10.1.2012, 22:12 |
|||
|
||||
Mirkes |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 586 Регистрация: 18.8.2011 Где: Красноярск Репутация: 7 Всего: 17 |
Есть подозрение, что вот этот фрагмент внесет погрешность. К сожалению пора на работу и нет времени проверить. Как только буду готов - напишу.
По поводу эффективности алгоритмов - я уже написал, что алгоритм не оптимизирован. Успел набросать на основе метода Dummy свой метод.
Нужно провести тест для проверки возникновения различий. Разница точно возникла, но мое время истекло. Вернусь - проверю что правильно. -------------------- Mirkes |
|||
|
||||
Mirkes |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 586 Регистрация: 18.8.2011 Где: Красноярск Репутация: 7 Всего: 17 |
Принял экзамен, теперь можно сдавать экзамен на владение датами.
В ходе ряда экспериментов установил, что пользоваться функцией TimeUnit.DAYS.convert для вычисления числа дней надо предельно акуратно, поскольку она имеет дурную привычку учитывать переоз на зимнее/летнее время, даже если его не было. Или перевод времени можно отключить? Сравнение FastDiff Dummy, и моего stag в следующей редакции:
Сравнение производилось следующим способом. Начальная дата выбиралась и задавалась вручную. В качестве конечной даты рассматривались все даты начиная с 11.01.2012 в течении 370 дней - чуть больше года. Все совпало при дате начала 01.08.2008. Различия установлены в следующих случаях: стартовая дата 02.08.2008 отличия в случаях (плюс по одному случаю совпадения) Дата конца FastDiff Dummy Мой stag 29.02.2012 27 days 6 month 3 years 27 days 6 month 3 years 01.03.2012 30 days 6 month 3 years 28 days 6 month 3 years 02.03.2012 0 days 7 month 3 years 0 days 7 month 3 years 30.04.2012 28 days 8 month 3 years 28 days 8 month 3 years 01.05.2012 30 days 8 month 3 years 29 days 8 month 3 years 02.05.2012 0 days 9 month 3 years 0 days 9 month 3 years Дальше видимо можно не продолжать. Вопрос о том, что есть правильно, конечно спорный, но вывод моего метода мне гораздо приятней. Если это нужно, то описание расчетов разницы дат можно добавить в статью по работе с датами в Java в FAQ -------------------- Mirkes |
|||
|
||||
Dummy |
|
||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 263 Регистрация: 21.5.2007 Репутация: 9 Всего: 19 |
И в изначальном варианте не мог быть оптимизирован. Кроме того, выдавал отрицательное количество месяцев на некоторых данных.
Cогласен ![]() |
||||
|
|||||
jk1 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 1168 Регистрация: 17.10.2008 Где: Санкт-Петербург Репутация: 40 Всего: 75 |
Это определяется установленой TimeZone, конкретно её параметром DST. Не уверен, вышел ли уже патч на отмену перехода на летнее(или зимнее, не помню) время. В качестве быстрого фикса я как-то раз подбирал зону UTC+4 без DST, результат совпадал с часами на стене. Но такой хак уберет переход вообще, то есть время в прошлом (когда переход еще имел место быть) может считаться ошибочно. -------------------- Opinions are like assholes — everybody has one |
|||
|
||||
Dummy |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 263 Регистрация: 21.5.2007 Репутация: 9 Всего: 19 |
Поправил свой метод подсчета (который по историческим причинам носит название fastDiff
![]()
Это сообщение отредактировал(а) Dummy - 11.1.2012, 16:17 |
|||
|
||||
Mirkes |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 586 Регистрация: 18.8.2011 Где: Красноярск Репутация: 7 Всего: 17 |
Полностью согласен
![]() -------------------- Mirkes |
|||
|
||||
jk1 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 1168 Регистрация: 17.10.2008 Где: Санкт-Петербург Репутация: 40 Всего: 75 |
Просто для сравнения приведу пример, как сделать тоже самое библиотекой Joda Time
Почувствуйте разницу) -------------------- Opinions are like assholes — everybody has one |
|||
|
||||
Dummy |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 263 Регистрация: 21.5.2007 Репутация: 9 Всего: 19 |
Круто ![]() ![]() Добавлено @ 00:30 Не знаю, часто ли бывает полезен полученный результат в других задачах, помимо расчета стажа ![]() Оффтоп: попытался плюсануть участникам дискуссии за полезный тред. Но что-то плюсовалка не работает... Это сообщение отредактировал(а) Dummy - 12.1.2012, 01:11 |
|||
|
||||
jk1 |
|
||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 1168 Регистрация: 17.10.2008 Где: Санкт-Петербург Репутация: 40 Всего: 75 |
Топикстартер хотел только стандартными средствами. Даже жирным шрифтом выделил в первом посте.
Не знаю, как именно Вы меряете, но с динамически компилируемыми языками не все так просто. У меня как раз завалялась хорошая статья по теме
Репутация на форуме совсем отвалилась: ни посмотреть, ни плюсануть( Это сообщение отредактировал(а) jk1 - 12.1.2012, 10:29 -------------------- Opinions are like assholes — everybody has one |
||||||
|
|||||||
Mirkes |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 586 Регистрация: 18.8.2011 Где: Красноярск Репутация: 7 Всего: 17 |
Провел полный тест по точности. Ниже код тестера (возможно не самый оптимальный, но вплне соответсвующий требованиям
![]()
Вывод организован так, чтобы при простом копировании в Excel получать внятную таблицу Результаты сравнения При началной дате 01.08.2008 Все результаты, кроме грубых совпали. При начальной дате 02.08.2008 ошибка в выводе fastDiff для 01.08.2012: 29 дней 11 месяцев 4 года. Правильный ответ 30 дней 11 месяцев 3 года. При начальной дате 02.08.2008 ошибка в выводе fastDiff для 1 и 2 августа 2012. Число дней на 1 меньше, а число лет на 1 больше. При всех начальных датах до 29.08.2008 ошибка в выводе fastDiff для дней с 01 по дату начала-1 августа 2012. Ошибка та же. Решил перепроверить последнюю версию fastDiff. Все точно. По крайней мере я ошибок не нашел. В чем глюк - не знаю. При начальной дате 30.08.2008 число ошибок возрастает. неправильно подсчитано числ дней за все дни с 01.03.2012 по 29.03.2012 и с 01.08.2012 по 29.08.2012. При начальной дате 30.08.2008 возникло одн разночтение между stag и Joda Time: 29.02.2012 stag вывел 30 дней 5 месяцев и 3 года, а Joda Time - 0 дней 6 месяцев и 3 года. Что из этих ответов считать правильным весьма спорный вопрос. При начальной дате 31.08.2008 fastDiff врет в числе дней во всех месяцах, которые короче 31 дня. Разночтения между stag и Joda Time возникают в последний день каждого месяца, который короче чем 31 день. Если разночтения между stag и Joda Time носят спорный характер, то с fastDiff нужно разобраться. Вернусь с работы - попробую выяснить причину. -------------------- Mirkes |
|||
|
||||
Dummy |
|
||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 263 Регистрация: 21.5.2007 Репутация: 9 Всего: 19 |
Знаю. Недавно читал вот такой замечательный материал: статья с JavaOne. Поэтому постоянно говорю, что мои подсчеты, скорее всего, грубоваты, хотя перед тестами я прогреваю JVM.
Спасибо за тщательность! Поковыряю код, как будет время. Это сообщение отредактировал(а) Dummy - 12.1.2012, 11:18 |
||||
|
|||||
Stolzen |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1041 Регистрация: 17.10.2005 Репутация: 23 Всего: 48 |
Ага, что-то шаманят... |
|||
|
||||
Mirkes |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 586 Регистрация: 18.8.2011 Где: Красноярск Репутация: 7 Всего: 17 |
В одном месте был мой глюк - перепутал дни и годы ![]() Второе чудо - свойство Calendar при установке, например, 30 февраля. Он не ругается, но и не ставит ![]() Чуть-чуть подшаманил код, теперь все работает одинаково, за исключением спорного момента по поводу 30 дней 2 месяцев 3 лет и 0 дней 3 месяцев 3 лет. Вот окончательный код fastDiff
По поводу скорости. Сначала прочитал предложенные Вами статьи. Это оказывается одна статья. Подготовил тестер вроде бы нормально. Проведу тестирование - напишу. -------------------- Mirkes |
|||
|
||||
Dummy |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 263 Регистрация: 21.5.2007 Репутация: 9 Всего: 19 |
Да, вы меня опередили. Я тоже нашел это и уже писал гневный и полный язвительности ответ про неравную конкуренцию и жалобу в антимонопольный комитет ![]()
Это чудо называется lenience. Контролируется через Calendar.setLenient(). Когда lenient = true (для Calendar это значение по умолчанию), календарь автоматически пытается транслировать некорректные даты. Например, 35 декабря 2008 года будет переведено в 4 января 2009. А 31 февраля 2012 - во 2-е марта 2012. Естественно, в fastDiff() это приводило к сползанию месяцев и чисел и краху моего алгоритма в ряде случаев. Поэтому лучше явно выставить при таких расчетах Calendar.setLenient(false) для всех используемых календарей. Тогда при установке неправильной даты мы сразу получим IllegalArgumentException. Это сообщение отредактировал(а) Dummy - 12.1.2012, 13:39 |
|||
|
||||
Mirkes |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 586 Регистрация: 18.8.2011 Где: Красноярск Репутация: 7 Всего: 17 |
Подвел результаты теста на скорость.
Для разогрева JVM использовал предыдущий вариант сраввения расчетов по всем четырем методам за год run(). в качестве самого теста - следующий код speed().
Результат обработал статистически. Стандартное отклонение менее 2% от средней величины. Расход времени на один расчет в мс: robust fastDiff stage joda 231 433 430 276 Так что по моим данным Joda Time работает на треть быстрее fastDiff и лишь чуть медленнее чем robust. Так что выбор достаточно прост: Если отклонение в пару дней роли не играет - используем грубый метод. Если нужно быстро и точно - Joda Time Если строгое ограничение - стандартные библиотеки и нужна точность - fastDiff. Теперь видимо окончательно все. ![]() ![]() -------------------- Mirkes |
|||
|
||||
arcsupport |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 725 Регистрация: 24.10.2008 Репутация: 1 Всего: 2 |
Mirkes, не могли бы Вы, пожалуйста, привести аналитические выражения и численный пример для выполненных Вами статистических обработок результатов.
|
|||
|
||||
Mirkes |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 586 Регистрация: 18.8.2011 Где: Красноярск Репутация: 7 Всего: 17 |
По сути ничего особого не делал.
Взял результат выполнения программы приведенной выше. Для чистоты эксперимента прилагаю полностью текст программы
Время счета на моем буке составило 20 минут. Дальше в MS EXCEL отсортировал вывод по первому полю и отделил выводы всех методов друг от друга. Для результатов каждого метода выполнил следующую обработку: 1. Отсортировал по времени выполнения. 2. Выкинул самый маленький и самый большой результаты. 3. Для оставшихся 100 значений рассчитал среднее и стандартное отклонение Собственно и вся обработка ![]() Каждого было по 102 штуки. -------------------- Mirkes |
|||
|
||||
arcsupport |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 725 Регистрация: 24.10.2008 Репутация: 1 Всего: 2 |
Mirkes, Вас не смущает, что формулы для расчетов стандартной ошибки и стандартного отклонения, реализованные в Excel, отличаются от традиционных русских формул, приведенных в учебниках?
|
|||
|
||||
Mirkes |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 586 Регистрация: 18.8.2011 Где: Красноярск Репутация: 7 Всего: 17 |
Нет, не смущает. Во первых среднее там считалось так же, во вторых стандартное отклонение при 100 запусках будет отличаться от канонической формулы в корень из 99/100=0.9949 раза, что никак не влияет на корректность результата. Господа, большое спасибо за ссылку на статью по измерению скорости. Автор оказался парнем, которого я когда-то учил информатике в КЛШ. Мы с ним списались и он по собственной инициативе провел серию экспериментов с нашими методами. Его мнение и его результаты привожу ниже
Если кому-то интересно, логи могу выложить. Еще раз спасибо за ссылку. -------------------- Mirkes |
|||
|
||||
Mirkes |
|
||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 586 Регистрация: 18.8.2011 Где: Красноярск Репутация: 7 Всего: 17 |
Уточнил смысл приведенных величин и получил вот какую статистику
означает следующее
Результат убойный - почти с точностью до наоборот по отношению к моим выводам ![]() Это сообщение отредактировал(а) Mirkes - 14.1.2012, 17:03 -------------------- Mirkes |
||||
|
|||||
Dummy |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 263 Регистрация: 21.5.2007 Репутация: 9 Всего: 19 |
Хм. Прочитав, сначала был эмоционально напуган, а потом возник вопрос:
- это все-таки величины в каких единицах? Количество отработавших вызовов за миллисекунду? Это сообщение отредактировал(а) Dummy - 15.1.2012, 22:28 |
|||
|
||||
Mirkes |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 586 Регистрация: 18.8.2011 Где: Красноярск Репутация: 7 Всего: 17 |
Наконец разобрался с этими величинами и провел свои тесты. Результаты разборки я суммировал в следующей теме Измерение скорости. Измеряется действительно число вызовов за милисекунду. Относительно наших методов мой результат следующий (в порядке убывания скорости) robust 0.780+-0.009 fastDiff 0.762+-0.004 joda 0.712+-0.005 stag 0.525+-0.002 результаты Алексея Шепилева абсолютно аналогичны. Так что объединенный разум VinGrad побил JodaTime! Ура Нам!! ![]() ![]() Это сообщение отредактировал(а) Mirkes - 16.1.2012, 18:49 -------------------- Mirkes |
|||
|
||||
![]() ![]() ![]() |
Правила форума "Java" | |
|
Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Java: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |