Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Стандартные календарные расчеты 
:(
    Опции темы
jk1
Дата 11.1.2012, 15:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 40
Всего: 75



Цитата

В ходе ряда экспериментов установил, что пользоваться функцией TimeUnit.DAYS.convert для вычисления числа дней надо предельно акуратно, поскольку она имеет дурную привычку учитывать переоз на зимнее/летнее время, даже если его не было. Или перевод времени можно отключить?


Это определяется установленой TimeZone, конкретно её параметром DST. Не уверен, вышел ли уже патч на отмену перехода на летнее(или зимнее, не помню) время.
В качестве быстрого фикса я как-то раз подбирал зону UTC+4 без DST, результат совпадал с часами на стене. Но такой хак уберет переход вообще, то есть время в прошлом (когда переход еще имел место быть) может считаться ошибочно.


--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
Dummy
Дата 11.1.2012, 16:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 263
Регистрация: 21.5.2007

Репутация: 9
Всего: 19



Поправил свой метод подсчета (который по историческим причинам носит название fastDiff smile). Теперь он выдает результаты, приятные всем. Кроме того, не используются миллисекунды, а значит, перевод часов не должен портить результат, как в варианте с TimeUnit (или я неправ?)
Код

public static void fastDiff(Calendar past, Calendar today) {        
    int years = today.get(Calendar.YEAR) - past.get(Calendar.YEAR);

    int monthsInYear = past.getMaximum(Calendar.MONTH) + 1;

    int pastMonth = past.get(Calendar.MONTH);
    int todayMonth = today.get(Calendar.MONTH);

    int months;

    if (pastMonth > todayMonth) {
        years--;
        months = monthsInYear - pastMonth + todayMonth;
    } else {
        months = todayMonth - pastMonth;
    }

    int pastDays = past.get(Calendar.DAY_OF_MONTH);
    int todayDays = today.get(Calendar.DAY_OF_MONTH);

    int days;

    if (pastDays > todayDays) {
        Calendar tmp = (Calendar)today.clone();
        tmp.add(Calendar.MONTH, -1);
        tmp.set(Calendar.DAY_OF_MONTH, pastDays);

        days = tmp.getActualMaximum(Calendar.DAY_OF_MONTH) - tmp.get(Calendar.DAY_OF_MONTH) + todayDays;
        months--;
    } else {
        days = todayDays - pastDays;
    }

    if (months < 0) {
        years--;
        months = monthsInYear + months;
    }

    System.out.printf("Fast diff: %d years %d months %d days\n", years, months, days);
}


Это сообщение отредактировал(а) Dummy - 11.1.2012, 16:17
PM MAIL   Вверх
Mirkes
Дата 11.1.2012, 19:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 586
Регистрация: 18.8.2011
Где: Красноярск

Репутация: 7
Всего: 17



Полностью согласен smile . Вопрос, стоит ли дописывать в FAQ в статью про работу с датами?


--------------------
Mirkes
PM MAIL   Вверх
jk1
Дата 11.1.2012, 20:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 40
Всего: 75



Просто для сравнения приведу пример, как сделать тоже самое библиотекой Joda Time

Код

Period p = new Period(startDate, endDate, PeriodType.yearMonthDay());


Почувствуйте разницу)


--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
Dummy
Дата 12.1.2012, 00:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 263
Регистрация: 21.5.2007

Репутация: 9
Всего: 19



Цитата(jk1 @  11.1.2012,  20:39 Найти цитируемый пост)
Почувствуйте разницу) 

Крутоsmile  Почему раньше не сказал? Мы же тут Calendar перепахали и в хвост и в гриву smile Результат, вроде, такой же. Хотя по моим самопальным замерам Period все же работает помедленнее, чем наше коллективное творчество. Ну, да не суть. Про Joda Time до этого сам я только словеса слышал. И, вроде, планируют когда-нибудь даже включить ее в JDK: JSR-310. Но это уже совсем другая история.

Добавлено @ 00:30
Цитата(Mirkes @  11.1.2012,  19:31 Найти цитируемый пост)
Вопрос, стоит ли дописывать в FAQ в статью про работу с датами?

Не знаю, часто ли бывает полезен полученный результат в других задачах, помимо расчета стажа smile А так - информация может быть полезной, например, программистам мобильных JVM, которые, возможно, не захотят таскать за собой полметра Joda Time ради подобного подсчета.

Оффтоп: попытался плюсануть участникам дискуссии за полезный тред. Но что-то плюсовалка не работает...

Это сообщение отредактировал(а) Dummy - 12.1.2012, 01:11
PM MAIL   Вверх
jk1
Дата 12.1.2012, 08:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 40
Всего: 75



Цитата

Круто  Почему раньше не сказал?


Топикстартер хотел только стандартными средствами. Даже жирным шрифтом выделил в первом посте.

Цитата

Хотя по моим самопальным замерам Period все же работает помедленнее, чем наше коллективное творчество. 


Не знаю, как именно Вы меряете, но с динамически компилируемыми языками не все так просто. У меня как раз завалялась хорошая статья по теме

Цитата

попытался плюсануть участникам дискуссии за полезный тред. Но что-то плюсовалка не работает...


Репутация на форуме совсем отвалилась: ни посмотреть, ни плюсануть(

Это сообщение отредактировал(а) jk1 - 12.1.2012, 10:29


--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
Mirkes
Дата 12.1.2012, 09:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 586
Регистрация: 18.8.2011
Где: Красноярск

Репутация: 7
Всего: 17



Провел полный тест по точности. Ниже код тестера (возможно не самый оптимальный, но вплне соответсвующий требованиям  smile )
Код

import java.text.SimpleDateFormat;

import java.util.Calendar;
import java.util.concurrent.TimeUnit;

import org.joda.time.Period;
import org.joda.time.PeriodType;


//import org.joda.time.Data;


public class Days {

    public static void main(String[] arg) {
        new Days().run();

    }

    private void run() {
        // Create three arrays to results
        int rob[] = new int[3];
        int jodat[] = new int[3];
        int fast[] = new int[3];
        int stagg[] = new int[3];


        Calendar past = Calendar.getInstance();
        past.set(2008, Calendar.AUGUST, 1); // 2008-08-30
        Calendar today = Calendar.getInstance(); // today

        SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy");
        System.out.println(format.format(past.getTime()));

        // Готовим швпку таблицы
        System.out.println("Сегодня" + '\t' + "robust" + '\t' + '\t' + '\t' + "fast" + '\t' + '\t' + '\t' + "stag" +
                           '\t' + '\t' + '\t' + "joda time" + '\t' + '\t' + '\t' + "отклонения");
        System.out.println("" + '\t' + "дней" + '\t' + "месяцев" + '\t' + "лет" + '\t' + "дней" + '\t' + "месяцев" +
                           '\t' + "лет" + '\t' + "дней" + '\t' + "месяцев" + '\t' + "лет" + '\t' + "дней" + '\t' +
                           "месяцев" + '\t' + "лет" + '\t' + "r/f" + '\t' + "f/s" + '\t' + "s/j");
        for (int i = 0; i < 370; i++) {
            System.out.print(format.format(today.getTime()));
            robust(past, today, rob);
            fastDiff(past, today, fast);
            stag(past, today, stagg);
            joda(past, today, jodat);
            print(rob);
            print(fast);
            print(stagg);
            print(jodat);
            printDif(rob,fast);
            printDif(stagg,fast);
            printDif(stagg,jodat);
            System.out.println();

            today.add(Calendar.DAY_OF_MONTH, 1);
            //            System.out.printf("Fast diff: %d years %d months %d days\n", years, months, days);
        }

    }

    public void print(int[] per) {
        for (int i = 0; i < 3; i++) {
            System.out.print("" + '\t' + per[i]);
        }
    }

    public void printDif(int[] per1, int[] per2) {
        if ((per1[0] == per2[0]) && (per1[1] == per2[1]) && (per1[2] == per2[2]))
            System.out.print("" + '\t' + "");
        else
            System.out.print("" + '\t' + "1");
    }


    public void robust(Calendar past, Calendar today, int[] rob) {
        Calendar diff = Calendar.getInstance();
        diff.setTimeInMillis(today.getTimeInMillis() - past.getTimeInMillis());
        rob[2] = diff.get(Calendar.YEAR) - 1970;
        rob[1] = diff.get(Calendar.MONTH);
        rob[0] = diff.get(Calendar.DAY_OF_MONTH);
    }

    public void fastDiff(Calendar past, Calendar today, int[] per) {
        per[2] = today.get(Calendar.YEAR) - past.get(Calendar.YEAR);
        int monthsInYear = past.getMaximum(Calendar.MONTH) + 1;
        int pastMonth = past.get(Calendar.MONTH);
        int todayMonth = today.get(Calendar.MONTH);
        if (pastMonth > todayMonth) {
            per[2]--;
            per[1] = monthsInYear - pastMonth + todayMonth;
        } else {
            per[1] = todayMonth - pastMonth;
        }
        int pastDays = past.get(Calendar.DAY_OF_MONTH);
        int todayDays = today.get(Calendar.DAY_OF_MONTH);
        if (pastDays > todayDays) {
            Calendar tmp = (Calendar)today.clone();
            tmp.add(Calendar.MONTH, -1);
            tmp.set(Calendar.DAY_OF_MONTH, pastDays);

            per[0] = tmp.getActualMaximum(Calendar.DAY_OF_MONTH) - tmp.get(Calendar.DAY_OF_MONTH) + todayDays;
            per[1]--;
        } else {
            per[0] = todayDays - pastDays;
        }

        if (per[1] < 0) {
            per[0]--;
            per[1] = monthsInYear + per[1];
        }
    }

    public void stag(Calendar past, Calendar today, int[] per) {
        per[2] = today.get(Calendar.YEAR) - past.get(Calendar.YEAR);

        int monthsInYear = past.getMaximum(Calendar.MONTH) + 1;
        int pastMonth = past.get(Calendar.MONTH);
        int todayMonth = today.get(Calendar.MONTH);
        if (pastMonth > todayMonth) {
            per[2]--;
            per[1] = monthsInYear - pastMonth + todayMonth;
        } else {
            per[1] = todayMonth - pastMonth;
        }
        int pastDays = past.get(Calendar.DAY_OF_MONTH);
        int todayDays = today.get(Calendar.DAY_OF_MONTH);
        if (pastDays > todayDays) {
            per[1]--;
        }
        if (per[1] < 0) {
            per[2]--;
            per[1] = monthsInYear + per[1];
        }
        Calendar work = (Calendar)past.clone();
        work.add(Calendar.YEAR, per[2]);
        work.add(Calendar.MONTH, per[1]);
        per[0] =
                (int)TimeUnit.DAYS.convert(today.getTimeInMillis() - work.getTimeInMillis() + 3600000, TimeUnit.MILLISECONDS);
    }

    public void joda(Calendar past, Calendar today, int[] per) {
        Period p = new Period(past.getTimeInMillis(), today.getTimeInMillis(), PeriodType.yearMonthDay());
        per[0] = p.getDays();
        per[1] = p.getMonths();
        per[2] = p.getYears();
    }

}

Вывод организован так, чтобы при простом копировании в 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
PM MAIL   Вверх
Dummy
Дата 12.1.2012, 11:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 263
Регистрация: 21.5.2007

Репутация: 9
Всего: 19



Цитата(jk1 @  12.1.2012,  08:32 Найти цитируемый пост)
Не знаю, как именно Вы меряете, но с динамически компилируемыми языками не все так просто. У меня как раз завалялась хорошая статья по теме

Знаю. Недавно читал вот такой замечательный материал: статья с JavaOne. Поэтому постоянно говорю, что мои подсчеты, скорее всего, грубоваты, хотя перед тестами я прогреваю JVM.
Цитата(Mirkes @  12.1.2012,  09:18 Найти цитируемый пост)
Если разночтения между stag и Joda Time носят спорный характер, то с fastDiff нужно разобраться.

Спасибо за тщательность! Поковыряю код, как будет время.

Это сообщение отредактировал(а) Dummy - 12.1.2012, 11:18
PM MAIL   Вверх
Stolzen
Дата 12.1.2012, 11:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1041
Регистрация: 17.10.2005

Репутация: 23
Всего: 48



Цитата(jk1 @  12.1.2012,  09:32 Найти цитируемый пост)
Репутация на форуме совсем отвалилась: ни посмотреть, ни плюсануть(

Ага, что-то шаманят...


--------------------
datatalks.ru - анализ данных, статистика, машинное обучение
PM MAIL WWW   Вверх
Mirkes
Дата 12.1.2012, 12:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 586
Регистрация: 18.8.2011
Где: Красноярск

Репутация: 7
Всего: 17



Цитата(Dummy @  12.1.2012,  11:15 Найти цитируемый пост)
Цитата(Mirkes @  12.1.2012,  09:18 )Если разночтения между stag и Joda Time носят спорный характер, то с fastDiff нужно разобраться.Спасибо за тщательность! Поковыряю код, как будет время.

В одном месте был мой глюк - перепутал дни и годы  smile . 
Второе чудо - свойство Calendar при установке, например, 30 февраля. Он не ругается, но и не ставит  smile .
Чуть-чуть подшаманил код, теперь все работает одинаково, за исключением спорного момента по поводу 30 дней 2 месяцев 3 лет и 0 дней 3 месяцев 3 лет.
Вот окончательный код fastDiff
Код

    public void fastDiff(Calendar past, Calendar today, int[] per) {
        per[2] = today.get(Calendar.YEAR) - past.get(Calendar.YEAR);
        int monthsInYear = past.getMaximum(Calendar.MONTH) + 1;
        int pastMonth = past.get(Calendar.MONTH);
        int todayMonth = today.get(Calendar.MONTH);
        if (pastMonth > todayMonth) {
            per[2]--;
            per[1] = monthsInYear - pastMonth + todayMonth;
        } else {
            per[1] = todayMonth - pastMonth;
        }
        int pastDays = past.get(Calendar.DAY_OF_MONTH);
        int todayDays = today.get(Calendar.DAY_OF_MONTH);
        if (pastDays > todayDays) {
            Calendar tmp = (Calendar)today.clone();
            tmp.add(Calendar.MONTH, -1);
            if (tmp.getActualMaximum(Calendar.DAY_OF_MONTH) <= pastDays) {
                per[0] = todayDays;
            } else {
                tmp.set(Calendar.DAY_OF_MONTH, pastDays);
                per[0] = tmp.getActualMaximum(Calendar.DAY_OF_MONTH) - tmp.get(Calendar.DAY_OF_MONTH) + todayDays;
            }
            per[1]--;
        } else {
            per[0] = todayDays - pastDays;
        }
        if (per[1] < 0) {
            per[2]--;
            per[1] = monthsInYear + per[1];
        }
    }

По поводу скорости. Сначала прочитал предложенные Вами статьи. Это оказывается одна статья.
Подготовил тестер вроде бы нормально. Проведу тестирование - напишу.


--------------------
Mirkes
PM MAIL   Вверх
Dummy
Дата 12.1.2012, 13:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 263
Регистрация: 21.5.2007

Репутация: 9
Всего: 19



Цитата(Mirkes @  12.1.2012,  12:43 Найти цитируемый пост)
В одном месте был мой глюк - перепутал дни и годы  smile . 

Да, вы меня опередили. Я тоже нашел это и уже писал гневный и полный язвительности ответ про неравную конкуренцию и жалобу в антимонопольный комитет smile 

Цитата(Mirkes @  12.1.2012,  12:43 Найти цитируемый пост)
Второе чудо - свойство Calendar при установке, например, 30 февраля. Он не ругается, но и не ставит  smile .

Это чудо называется 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
PM MAIL   Вверх
Mirkes
Дата 12.1.2012, 14:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 586
Регистрация: 18.8.2011
Где: Красноярск

Репутация: 7
Всего: 17



Подвел результаты теста на скорость.
Для разогрева JVM использовал предыдущий вариант сраввения расчетов по всем четырем методам за год run().
в качестве самого теста - следующий код speed().
Код

    public static void main(String[] arg) {
        new Days().run();
        new Days().speed();
    }

    private void speed() {
        final int count = 1000000;
        final int max = 102;
        int rob[] = new int[3];
        long tim1,tim2;
        Calendar past = Calendar.getInstance();
        past.set(2008, Calendar.AUGUST, 31); // 2008-08-30
        Calendar today = Calendar.getInstance(); // today
        today.set(2012, Calendar.MARCH, 1);
        int sum;
        for (int i = 0; i < max; i++) {
            sum = 0;
            tim1=System.nanoTime();
            for (int j = 0; j < count; j++) {
                robust(past, today, rob);
                sum += rob[2];
            }
            tim2=System.nanoTime();
            System.out.println("robust"+'\t'+(tim2-tim1)+'\t'+sum);
            sum = 0;
            tim1=System.nanoTime();
            for (int j = 0; j < count; j++) {
                fastDiff(past, today, rob);
                sum += rob[2];
            }
            tim2=System.nanoTime();
            System.out.println("fastDiff"+'\t'+(tim2-tim1)+'\t'+sum);
            sum = 0;
            tim1=System.nanoTime();
            for (int j = 0; j < count; j++) {
                stag(past, today, rob);
                sum += rob[2];
            }
            tim2=System.nanoTime();
            System.out.println("stag"+'\t'+(tim2-tim1)+'\t'+sum);
            sum = 0;
            tim1=System.nanoTime();
            for (int j = 0; j < count; j++) {
                joda(past, today, rob);
                sum += rob[2];
            }
            tim2=System.nanoTime();
            System.out.println("joda"+'\t'+(tim2-tim1)+'\t'+sum);
        }
    }

Результат обработал статистически. Стандартное отклонение менее 2% от средней величины.
Расход времени на один расчет в мс:
robust    fastDiff    stage    joda
231    433    430    276
Так что по моим данным Joda Time работает на треть быстрее fastDiff и лишь чуть медленнее чем robust.
Так что выбор достаточно прост:
Если отклонение в пару дней роли не играет - используем грубый метод.
Если нужно быстро и точно - Joda Time
Если строгое ограничение - стандартные библиотеки и нужна точность - fastDiff.

Теперь видимо окончательно все.  smile  smile 


--------------------
Mirkes
PM MAIL   Вверх
arcsupport
Дата 12.1.2012, 21:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 725
Регистрация: 24.10.2008

Репутация: 1
Всего: 2



Mirkes, не могли бы Вы, пожалуйста, привести аналитические выражения и численный пример для выполненных Вами статистических обработок результатов.
PM MAIL   Вверх
Mirkes
Дата 14.1.2012, 10:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 586
Регистрация: 18.8.2011
Где: Красноярск

Репутация: 7
Всего: 17



По сути ничего особого не делал. 
Взял результат выполнения программы приведенной выше. Для чистоты эксперимента прилагаю полностью текст программы
Код

package tests;

import java.text.SimpleDateFormat;

import java.util.Calendar;
import java.util.concurrent.TimeUnit;

import org.joda.time.Period;
import org.joda.time.PeriodType;


//import org.joda.time.Data;


public class Days {

    public static void main(String[] arg) {
        new Days().run();
        new Days().speed();
    }

    private void speed() {
        final int count = 1000000;
        final int max = 102;
        int rob[] = new int[3];
        long tim1,tim2;
        Calendar past = Calendar.getInstance();
        past.set(2008, Calendar.AUGUST, 31); // 2008-08-30
        Calendar today = Calendar.getInstance(); // today
        today.set(2012, Calendar.MARCH, 1);
        int sum;
        for (int i = 0; i < max; i++) {
            sum = 0;
            tim1=System.nanoTime();
            for (int j = 0; j < count; j++) {
                robust(past, today, rob);
                sum += rob[2];
            }
            tim2=System.nanoTime();
            System.out.println("robust"+'\t'+(tim2-tim1)+'\t'+sum);
            sum = 0;
            tim1=System.nanoTime();
            for (int j = 0; j < count; j++) {
                fastDiff(past, today, rob);
                sum += rob[2];
            }
            tim2=System.nanoTime();
            System.out.println("fastDiff"+'\t'+(tim2-tim1)+'\t'+sum);
            sum = 0;
            tim1=System.nanoTime();
            for (int j = 0; j < count; j++) {
                stag(past, today, rob);
                sum += rob[2];
            }
            tim2=System.nanoTime();
            System.out.println("stag"+'\t'+(tim2-tim1)+'\t'+sum);
            sum = 0;
            tim1=System.nanoTime();
            for (int j = 0; j < count; j++) {
                joda(past, today, rob);
                sum += rob[2];
            }
            tim2=System.nanoTime();
            System.out.println("joda"+'\t'+(tim2-tim1)+'\t'+sum);
        }
    }

    private void run() {
        // Create three arrays to results
        int rob[] = new int[3];
        int jodat[] = new int[3];
        int fast[] = new int[3];
        int stagg[] = new int[3];


        Calendar past = Calendar.getInstance();
        past.set(2008, Calendar.AUGUST, 31); // 2008-08-30
        Calendar today = Calendar.getInstance(); // today

        SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy");
        System.out.println(format.format(past.getTime()));

        // Готовим швпку таблицы
        System.out.println("Сегодня" + '\t' + "robust" + '\t' + '\t' + '\t' + "fast" + '\t' + '\t' + '\t' + "stag" +
                           '\t' + '\t' + '\t' + "joda time" + '\t' + '\t' + '\t' + "отклонения");
        System.out.println("" + '\t' + "дней" + '\t' + "месяцев" + '\t' + "лет" + '\t' + "дней" + '\t' + "месяцев" +
                           '\t' + "лет" + '\t' + "дней" + '\t' + "месяцев" + '\t' + "лет" + '\t' + "дней" + '\t' +
                           "месяцев" + '\t' + "лет" + '\t' + "r/f" + '\t' + "f/s" + '\t' + "s/j");
        for (int i = 0; i < 370; i++) {
            System.out.print(format.format(today.getTime()));
            robust(past, today, rob);
            fastDiff(past, today, fast);
            stag(past, today, stagg);
            joda(past, today, jodat);
            print(rob);
            print(fast);
            print(stagg);
            print(jodat);
            printDif(rob, fast);
            printDif(stagg, fast);
            printDif(stagg, jodat);
            System.out.println();

            today.add(Calendar.DAY_OF_MONTH, 1);
            //            System.out.printf("Fast diff: %d years %d months %d days\n", years, months, days);
        }

    }

    public void print(int[] per) {
        for (int i = 0; i < 3; i++) {
            System.out.print("" + '\t' + per[i]);
        }
    }

    public void printDif(int[] per1, int[] per2) {
        if ((per1[0] == per2[0]) && (per1[1] == per2[1]) && (per1[2] == per2[2]))
            System.out.print("" + '\t' + "");
        else
            System.out.print("" + '\t' + "1");
    }


    public void robust(Calendar past, Calendar today, int[] rob) {
        Calendar diff = Calendar.getInstance();
        diff.setTimeInMillis(today.getTimeInMillis() - past.getTimeInMillis());
        rob[2] = diff.get(Calendar.YEAR) - 1970;
        rob[1] = diff.get(Calendar.MONTH);
        rob[0] = diff.get(Calendar.DAY_OF_MONTH);
    }

    public void fastDiff(Calendar past, Calendar today, int[] per) {
        per[2] = today.get(Calendar.YEAR) - past.get(Calendar.YEAR);
        int monthsInYear = past.getMaximum(Calendar.MONTH) + 1;
        int pastMonth = past.get(Calendar.MONTH);
        int todayMonth = today.get(Calendar.MONTH);
        if (pastMonth > todayMonth) {
            per[2]--;
            per[1] = monthsInYear - pastMonth + todayMonth;
        } else {
            per[1] = todayMonth - pastMonth;
        }
        int pastDays = past.get(Calendar.DAY_OF_MONTH);
        int todayDays = today.get(Calendar.DAY_OF_MONTH);
        if (pastDays > todayDays) {
            Calendar tmp = (Calendar)today.clone();
            tmp.add(Calendar.MONTH, -1);
            if (tmp.getActualMaximum(Calendar.DAY_OF_MONTH) <= pastDays) {
                per[0] = todayDays;
            } else {
                tmp.set(Calendar.DAY_OF_MONTH, pastDays);
                per[0] = tmp.getActualMaximum(Calendar.DAY_OF_MONTH) - tmp.get(Calendar.DAY_OF_MONTH) + todayDays;
            }
            per[1]--;
        } else {
            per[0] = todayDays - pastDays;
        }
        if (per[1] < 0) {
            per[2]--;
            per[1] = monthsInYear + per[1];
        }
    }

    public void stag(Calendar past, Calendar today, int[] per) {
        per[2] = today.get(Calendar.YEAR) - past.get(Calendar.YEAR);

        int monthsInYear = past.getMaximum(Calendar.MONTH) + 1;
        int pastMonth = past.get(Calendar.MONTH);
        int todayMonth = today.get(Calendar.MONTH);
        if (pastMonth > todayMonth) {
            per[2]--;
            per[1] = monthsInYear - pastMonth + todayMonth;
        } else {
            per[1] = todayMonth - pastMonth;
        }
        int pastDays = past.get(Calendar.DAY_OF_MONTH);
        int todayDays = today.get(Calendar.DAY_OF_MONTH);
        if (pastDays > todayDays) {
            per[1]--;
        }
        if (per[1] < 0) {
            per[2]--;
            per[1] = monthsInYear + per[1];
        }
        Calendar work = (Calendar)past.clone();
        work.add(Calendar.YEAR, per[2]);
        work.add(Calendar.MONTH, per[1]);
        per[0] =
                (int)TimeUnit.DAYS.convert(today.getTimeInMillis() - work.getTimeInMillis() + 3600000, TimeUnit.MILLISECONDS);
    }

    public void joda(Calendar past, Calendar today, int[] per) {
        Period p = new Period(past.getTimeInMillis(), today.getTimeInMillis(), PeriodType.yearMonthDay());
        per[0] = p.getDays();
        per[1] = p.getMonths();
        per[2] = p.getYears();
    }

}

Время счета на моем буке составило 20 минут.
Дальше в MS EXCEL отсортировал вывод по первому полю и отделил выводы всех методов друг от друга.
Для результатов каждого метода выполнил следующую обработку:
1. Отсортировал по времени выполнения.
2. Выкинул самый маленький и самый большой результаты.
3. Для оставшихся 100 значений рассчитал среднее и стандартное отклонение
Собственно и вся обработка  smile 
Каждого было по 102 штуки.


--------------------
Mirkes
PM MAIL   Вверх
arcsupport
Дата 14.1.2012, 14:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 725
Регистрация: 24.10.2008

Репутация: 1
Всего: 2



Mirkes, Вас не смущает, что формулы для расчетов стандартной ошибки и стандартного отклонения, реализованные в Excel, отличаются от традиционных русских формул, приведенных в учебниках?
PM MAIL   Вверх
Страницы: (3) Все 1 [2] 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1215 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.