d7d1cd
Apr 22 2013, 17:42
Привет всем. Делаю программу на ассемблере. Есть дата и время 2-х событий, которые хранятся в двоично-десятичном коде. Второе событие всегда происходит позже первого. Необходимо определить сколько времени прошло между этими событиями.
d7d1cd
Apr 23 2013, 02:45
Таймером? Каким образом? Мне же не отмерить промежуток времени надо, а определить его.
AlexFTF
Apr 23 2013, 04:40
А в чем проблема? От второго события отнять первое...
d7d1cd
Apr 23 2013, 08:23
Цитата(AlexFTF @ Apr 23 2013, 08:40)

А в чем проблема? От второго события отнять первое...
В этом и проблема. Как это сделать? Подскажите алгоритм...
Вы задаете вопросы, на которые настолько легко найти ответ в гугле и интернете, что возникают вопросы...
http://habrahabr.ru/post/112630/
d7d1cd
Apr 23 2013, 09:25
Цитата(decom @ Apr 23 2013, 13:01)

Вы задаете вопросы, на которые настолько легко найти ответ в гугле и интернете, что возникают вопросы...
http://habrahabr.ru/post/112630/Спасибо за ссылку на статью. Однако это не совсем то, что мне нужно.Точнее это совсем не то, что мне нужно. Мне не надо отмерять промежуток времени. Мне надо определить сколько прошло между 2-мя событиями секунд, минут, часов и суток.
rezident
Apr 23 2013, 10:17
Цитата(d7d1cd @ Apr 23 2013, 14:25)

Мне надо определить сколько прошло между 2-мя событиями секунд, минут, часов и суток.
Вообще-то вычисление времени проходят в первом полугодии третьего класса начальной школы
Это вовсе не бином Ньютона - переводите обе даты в нименьшие единицы измерения (секунды) и вычитаете одно число из другого. По больщому счету такие вычисления ничем не отличаются от функции измерения интервала времени "в попугаях", реализованной на таймере, о котором вам ранее намекали.
d7d1cd
Apr 23 2013, 10:49
Цитата(rezident @ Apr 23 2013, 14:17)

Вообще-то вычисление времени проходят в первом полугодии третьего класса начальной школы
Это вовсе не бином Ньютона - переводите обе даты в нименьшие единицы измерения (секунды) и вычитаете одно число из другого. По больщому счету такие вычисления ничем не отличаются от функции измерения интервала времени "в попугаях", реализованной на таймере, о котором вам ранее намекали.
На счет преобразования в наименьшую единицу измерения я полностью согласен. Однако осмелюсь повториться, что я пишу на ассемблере, поэтому ищу максимально простой алгоритм.
На счет преобразования: перевести в секунды минуты, часы и дни легко. Но как быть с месяцами и годами? Ведь в них не постоянное число секунд...
adnega
Apr 23 2013, 11:06
Цитата(rezident @ Apr 23 2013, 14:17)

...переводите обе даты в нименьшие единицы измерения (секунды) и вычитаете одно число из другого.
Например, так:
CODE
Начало эпохи 01.01.2000 00:00:00
Работает корректно до 2100 года.
//-----------------------------------------------------------------------------
//! \fn extern DWORD date_to_int(DWORD y, DWORD m, DWORD d)
//! \brief Преобразует дату в число.
//! \param y Год.
//! \param m Месяц.
//! \param d День месяца.
//! \return Номер дня по порядку от начала эпохи.
//! \sa int_to_date().
//-----------------------------------------------------------------------------
extern DWORD date_to_int(DWORD y, DWORD m, DWORD d);
//-----------------------------------------------------------------------------
//! \fn extern void int_to_date (const DWORD jd, DWORD *y, DWORD *m, DWORD *d)
//! \brief Преобразует число в дату.
//! \param jd Номер дня по порядку от начала эпохи.
//! \param y Указатель на переменную для года.
//! \param m Указатель на переменную для месяца.
//! \param d Указатель на переменную для дня месяца.
//! \sa date_to_int().
//-----------------------------------------------------------------------------
extern void int_to_date (const DWORD jd, DWORD *y, DWORD *m, DWORD *d);
//-----------------------------------------------------------------------------
// int date_to_int(int y, int m, int d)
//-----------------------------------------------------------------------------
DWORD date_to_int(DWORD y, DWORD m, DWORD d)
{
if(m < 3)
{
m += 12;
y -= 1;
}
return ((y * 1461) >> 2) + ((m * 306 + 7) / 10) + d - 730533;
}
//-----------------------------------------------------------------------------
// void int_to_date(DWORD jd, int *y, int *m, int *d)
//-----------------------------------------------------------------------------
void int_to_date(DWORD jd, DWORD *y, DWORD *m, DWORD *d)
{
int aa, bb, cc, dd, ee, mm, xx;
aa = jd + 2483589;
bb = (aa * 4 + 3) / 146097;
cc = aa - ((146097 * bb) >> 2);
dd = (4 * cc + 3) / 1461;
ee = cc - ((1461 * dd) >> 2);
mm = ((5 * ee + 2) * 13707) >> 21;
*d = ee - ((16043274 * mm + 209716) >> 19) + 1;
*m = mm + 3 - 12 * ((mm * 27) >> 8);
*y = 100 * bb + dd - 4800 + ((mm * 27) >> 8);
}
d7d1cd
Apr 23 2013, 11:57
Спасибо за код. Можно попросить прокомментировать строки функции, которая преобразует дату в число дней...
В коде похоже ошибка, надо бы проверить.
AlexFTF
Apr 24 2013, 04:15
Цитата(d7d1cd @ Apr 23 2013, 17:49)

Однако осмелюсь повториться, что я пишу на ассемблере, поэтому ищу максимально простой алгоритм.
Позвольте поинтересоваться почему Вы пишите программу на ассемблере, а не на Си? Ведь на Си гораздо проще и быстрее реализовать поставленную задачу...
d7d1cd
Apr 24 2013, 12:07
Цитата(AlexFTF @ Apr 24 2013, 08:15)

Позвольте поинтересоваться почему Вы пишите программу на ассемблере, а не на Си? Ведь на Си гораздо проще и быстрее реализовать поставленную задачу...
Я понимаю, что на С все проще. Однако я могу писать только на ассемблере. Причину такого выбора сказать не могу, так как это будет противоречить правилам данного форума.
Цитата(d7d1cd @ Apr 24 2013, 16:07)

Я понимаю, что на С все проще. Однако я могу писать только на ассемблере. Причину такого выбора сказать не могу, так как это будет противоречить правилам данного форума.
Какому пункту правил?
P.S. Я, например, пишу на Форт (Forth) и подозреваю что тоже нарушаю какой то пункт правил данного форума.

(на Си кстати тоже, как и на асм)
А судя по репликам прозвучащим в топике не относящихся к вопросу как задающего так и отвечающего то правила нарушают многие

а модераторы форума стоят рядышком и наблюдают за "засиранием" форума "непонятными" вопросами и "непонятными" ответами и "непонятно" где
они должны быть озвучены, а может сразу перейти ссылкой на FAQ или его допонить?
adnega
Apr 28 2013, 07:43
Цитата(d7d1cd @ Apr 23 2013, 15:57)

Спасибо за код. Можно попросить прокомментировать строки функции, которая преобразует дату в число дней...
Дело было давно, сейчас тонкостей не помню.
Возможно "формула Зеллера" из этой оперы.
В самом конце формулы будет вычитание большого числа - это сдвиг начало эпохи.
Цитата(decom @ Apr 23 2013, 16:51)

В коде похоже ошибка, надо бы проверить.
Перевод туда и обратно проверял числительно для всех дат от 2000 до 2099 года.
Можете показать проблемное место?
d7d1cd
Apr 30 2013, 16:50
Цитата(Kopa @ Apr 28 2013, 09:51)

Какому пункту правил?
Я не помню точно какой пункт, но он относится к запрету обсуждения дизасма чужих программ. Почему всем так интересно, чего это я пишу на асме, а не на Си? Всем интересно, а модераторы потом претензии предъявляют не всем, а тебе...
Мне не важен язык программы, мне нужен алгоритм. Так что кто может помочь, направляйте на путь истинный...
msalov
Apr 30 2013, 20:05
Такой наивный вопрос: а чем стандартная библиотека Си не угодила? Там есть функция работы со временем mktime, которая время в человеко-приемлемой форме переводит во время Unix (количество секунд с 01.01.1970 00:00:00). Ну а дальше разницу взять - дело тривиальное.
Цитата(msalov @ May 1 2013, 00:05)

Такой наивный вопрос: а чем стандартная библиотека Си не угодила? Там есть функция работы со временем mktime, которая время в человеко-приемлемой форме переводит во время Unix (количество секунд с 01.01.1970 00:00:00). Ну а дальше разницу взять - дело тривиальное.
Такое наивное сто двадцать пятое объяснение: Я ПИШУ НА АССЕМБЛЕРЕ!!!
Пишите хоть в машинных кодах.
Из моего сообщения вы могли бы почерпнуть, если бы не торопились с выводами, такие варианты:
* использовать библиотеку напрямую (если только у вас не орден велосипедостроителя 3ей степени), ведь из ПИСАНИЯ НА АССЕМБЛЕРЕ не следует невозможность использования библиотек;
* использовать исходный код (реализаций на Си предостаточно) что б реализовать алгоритм своими силами;
* бинарник нужной функции из библиотеки пропустить через дизассемблер, ручками выправить полученное до ассемблируемого вида, ведь вам же нужен АССЕМБЛЕР.
Stanislav
May 2 2013, 06:57
Цитата(d7d1cd @ May 1 2013, 09:35)

Такое наивное сто двадцать пятое объяснение: Я ПИШУ НА АССЕМБЛЕРЕ!!!
Извините, но при чём здесь Ассемблер?
Изучите основы систем счисления, а потом пишите хоть на суахили...
jack_avenger
May 3 2013, 19:06
Цитата(Stanislav @ May 2 2013, 09:57)

Извините, но при чём здесь Ассемблер?
Изучите основы систем счисления, а потом пишите хоть на суахили...
Сложно будет человеку на Ассемблере писать функции деления не на константу. Если быстродействие не кусается, то можно преобразование выполнять через отнимание в цикле сначала количества секунд в годе (с учетом высокосных), потом месяцы (например через масив количества секунд в месяце), сутки и т.д.
Цитата(jack_avenger @ May 3 2013, 23:06)

Сложно будет человеку на Ассемблере писать функции деления не на константу.
Если человек использует ассемблер, то эта функция у него уже есть.
jack_avenger
May 3 2013, 19:13
Цитата(adnega @ May 3 2013, 22:10)

Если человек использует ассемблер, то эта функция у него уже есть.
Не факт. Я даже в программе на С стараюсь избегать деления на что-либо отличное от степени двойки.
Цитата(jack_avenger @ May 3 2013, 23:13)

Не факт. Я даже в программе на С стараюсь избегать деления на что-либо отличное от степени двойки.
А как же вывод десятичных чисел на дисплей? Деление на константу 10.
В свое время делал на АСМе получается (частное и остаток) компактно и быстро, но с использованием команды умножения.
Функцию деления произвольно числа на произвольное число делал для кр1878ве1, МК51, AVR.
Заниматься вычитаниями можно, но зачем, когда можно взять и один раз написать нужную функцию?
jack_avenger
May 3 2013, 20:00
Цитата(adnega @ May 3 2013, 22:24)

А как же вывод десятичных чисел на дисплей? Деление на константу 10.
Использование деления на 10 для вывода на дисплей это немного "из пушки по воробьям".
У некоторых МSP (например у СС430) есть преобразователь BIN->BCD, и BCD->BIN. Обычно эти регистры сидят в адресном пространстве ЖКИ.
Если преобразователя нет, надо преобраз]овывать используя команду двоично-десятичного сложения dadd.x. Так в разы быстрее деления.
В С она доступна через __bcd_add_long().
Вот пример из книги "MSP430 Microcontroller Basics"
Код
; Assembly routine to convert 16-bit unsigned binary value to BCD
; Taken from Application Reports , section 5.5.3
; Called from C as: uint32_t UIntToBCD (uint16_t UIntValue );
; 16-bit parameter "UIntValue" passed in R12
; 32-bit value "UIntToBCD" returned in R13:R12
; Uses only the scratch registers R12 -R15 so no stacking necessary
;-----------------------------------------------------------------------
PUBLIC UIntToBCD ; Export symbol outside this file
RSEG CODE ; Essential as usual
UIntToBCD: ; Name of function as usual
mov.w R12 ,R14 ; Move input and leave R12 free for result
clr.w R12 ; Clear registers for result
clr.w R13
mov.w #0x0010 ,R15 ; Initialize loop counter to number of bits
LoopStart:
rla.w R14 ; Shift msb of input into carry bit
dadd.w R12 ,R12 ; R13:R12 = 2* R13:R12 + carry bit DECIMALLY
dadd.w R13 ,R13 ; lsword then msword
dec.w R15 ; Decrement loop counter
jnz LoopStart ; Repeat if nonzero
reta ; Return instruction in MSP430X
; ret ; Usual MSP430 return instruction
END
Господа, деление меня не волнует (так же как и умножение). Для своих целей я уже написал функции для деления и умножения. Причем они работают с 32-х разрядными числами.
Если не трудно, то покажите алгоритм определения разности между датами в минутах (точнее не нужно).
Вы уже достали своими детскими вопросами.
Вот алгоритм определения разности в минутах ВНУТРИ ОДНОГО ГОДА.
Дата А: 12.34 21/01/2013
Дата Ю: 17.35 05/05/2013
Определяем количество полных дней в каждой дате с начала года:
Дата А: январь 21 = 21
Дата Б: январь 31, февраль 28, март 31, апрель 30, май 5= 125
Определяем количество полных часов с начала даты
Дата А: 12
Дата Б: 17
Определяем количество минут с начала нового часа
Дата А:34
Дата Б:35
Уже известно что в сутках 24 часа или 1440 минут
А в одном часе 60 минут
Переводим в минуты:
Дата А дни 21*1440 = 30240, часы 12*60=720, минуты 34
Дата Б дни 125*1440 = 180000, часы 17*60=1020, минуты 35
Складываем минуты для каждой даты
Дата А: 30240+720+34=30994
Дата Б: 180000+1020+35=181055
Вычисляем разность между датами в минутах:
Разность: ДатаБ-ДатаА = 181055-30994=150061
Ответ: разность в минутах равна 150061 (сто пятьдесят тысяч шестьдесят одна минута)
Чтобы получить ответ в секундах надо умножить число на 60.
Ответ в секундах: 150061*60=9003660 (девять миллионов три тысячи шестьсот шестьдесят секунд)
Цитата(decom @ May 4 2013, 11:01)

Вы уже достали своими детскими вопросами.
Вот алгоритм определения разности в минутах ВНУТРИ ОДНОГО ГОДА.
Дата А: 12.34 21/01/2013
Дата Б: 17.35 05/05/2013
...
Ответ в секундах: 150061*60=9 003 660 (девять миллионов три тысячи шестьсот шестьдесят секунд)
А вот для произвольной даты внутри столетия (2000 - 2099 года)
Для первой даты: поскольку месяц меньше 3, то у года вычитаем единицу, а месяц увеличиваем на 12.
((2013 - 1) * 1461) / 4 + ((1 + 12) * 306 + 7) / 10 + 21 - 730533 =
734883 + 398 + 21 - 730533 = 4769
В секундах: ((4769 * 24 + 12) * 60 + 34) * 60 + 0 = 412 086 840
Для второй даты:
(2013 * 1461) / 4 + (5 * 306 + 7) / 10 + 5 - 730533 =
735248 + 153 + 5 - 730533 = 4873
В секундах: ((4873 * 24 + 17) * 60 + 35) * 60 + 0 = 421 090 500
Разница: 9 003 660
Полагаю ТС собирается сделать гаджет типа "сколько секунд я прожил. Поэтому ему надо с 1900 года.
Слесарь
May 4 2013, 17:07
Помнится, вопрос расчета времени по календарю не такой и простой как в приведенных формулах, помнится даже CTime от микрософт не всегда качественно справлялся с этой задачей. Если вопрос принципиален могу покапаться в архивах и привести парочку вариантов возникновения ошибки в реальных приложениях где производится расчет промежутка времени.
вот например
Код
CDate::CDate(const SYSTEMTIME &st)
{
/* Так как бывает летнее и зимнее время, возьмем
за базу полдень. Что бы перевод времени не влиял
на дату. То есть, если за базу берется полночь
переход на летнее время после зимнего может произвести
при вычислении BackDay() пропуск целой даты.
*/
CTime t( st.wYear, st.wMonth, st.wDay, 12, 0, 0 );
m_time = t;
}
Цитата(Слесарь @ May 4 2013, 21:07)

Помнится, вопрос расчета времени по календарю не такой и простой как в приведенных формулах
Возможно, но для 2000 - 2099 годов работает для любой даты. Проверял перебором.
Слесарь
May 4 2013, 17:31
странно, разве вам известно как распределится время в промежутке 2014 ... 2099 годах? Время ведь понятие человеческое, людям свойственно менять отношение к собственным понятиям. Вспомните Мюнхаузена с его 32 числом, ведь это нововведение вполне может быть легализовано в один прекрасный момент, как собственно недавняя приписка чуть более десятка дней к календарю.
haker_fox
May 6 2013, 03:35
QUOTE (Слесарь @ May 5 2013, 02:31)

странно, разве вам известно как распределится время в промежутке 2014 ... 2099 годах? Время ведь понятие человеческое, людям свойственно менять отношение к собственным понятиям. Вспомните Мюнхаузена с его 32 числом, ведь это нововведение вполне может быть легализовано в один прекрасный момент, как собственно недавняя приписка чуть более десятка дней к календарю.
При переводе даты в количество секунд (минут) нужно учитывать високосные годы. Как, написано много где. Вроде все. Количество дней в месяцах кроме февраля - фиксированное.
Слесарь
May 6 2013, 05:08
Рас читывать количество месяцев за промежуток времени по секундам, достаточно сомнительное занятие. Учитывать только секунды при расчете даты, это прямолинейное ориентирование только на один ориентир Солнце. Ошибка в расчете количества месяцев присутствует постоянно.
Кста есть значимые свидетельства ошибок таких расчетов, например католическая Пасха рассчитывается по григорианскому солнечному календарю (учитывается только солнечный год, календарь прямолинейный, как по секундам), католики часто нарушают правило праздновать Пасху в первое воскресенье после наступления полнолуния, которое выпадает на период после весеннего равноденствия. После празднования иудейской Пасхи, если случается совпадение, то правила предписывают перейти к полнолунию следующего месяца.
В настоящее время католическая пасха часто празднуется раньше иудейской, что строго запрещается церковными канонами.
Цитата(Слесарь @ May 4 2013, 21:31)

Время ведь понятие человеческое, людям свойственно менять отношение к собственным понятиям.
Все просто: приведенные формулы годятся для существующего сейчас календаря.
Когда календарь поменяют, тогда поменяем и формулы.
Привязываться к астрономической точности в рамках решаемой задачи явный перебор.
Эдак можно задачу и не решить... ведь в сутках не ровно 24 часа... да и вращается Земля вокруг
собственной оси с небольшим снижением оборотов...
А если два события происходят в разных точках пространства... или по разные стороны "линии перемены дат"...
Условностей много, и это еще без привлечения религий))
Сразу хочу сказать спасибо всем за помощь. Алгоритм приведенный adnega вполне подходит. Только объясните мне, почему если месяц меньше 3-х, то необходимо год уменьшить на 1, а количество месяцев увеличить на 12?
Цитата(d7d1cd @ May 6 2013, 18:29)

Только объясните мне, почему если месяц меньше 3-х, то необходимо год уменьшить на 1, а количество месяцев увеличить на 12?
Видимо, чтобы "изменчивый" февраль был в конце.
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.