Войти

Показать полную графическую версию : Конвертирование времени


novashdima
21-08-2012, 14:35
Добрый день. Не так давно решил переписать участки с говнокодом в программе, до этого не было времени, а функции были не важные, сейчас переработал два куска кода, но после исправления второго нечаянно обнаружил проблему. Сама функция занимается переводом секунд в минуты, часы... казалось, что проще, оказалось и тут проблема есть. Привожу код:
function ConvertTime(timeExt: Extended):string;
var m, w, d, h, min, sec: Int64;
begin
m := Trunc(Convert(timeExt, tuSeconds, tuMonths));
timeExt := timeExt - m * 2592000;
w := Trunc(Convert(timeExt, tuSeconds, tuWeeks));
timeExt := timeExt - w * 604800;
d := Trunc(Convert(timeExt, tuSeconds, tuDays));
timeExt := timeExt - d * 86400;
h := Trunc(Convert(timeExt, tuSeconds, tuHours));
timeExt := timeExt - h * 3600;
min := Trunc(Convert(timeExt, tuSeconds, tuMinutes));
sec := Trunc(timeExt - min * 60);
if m <> 0 then Result := IntToStr(m) + ' мес ';
if w <> 0 then Result := Result + IntToStr(w) + ' нед ';
if d <> 0 then Result := Result + IntToStr(d) + ' д ';
if h <> 0 then Result := Result + IntToStr(h) + ' ч ';
if min <> 0 then Result := Result + IntToStr(min) + ' м ';
if sec <> 0 then Result := Result + IntToStr(sec) + ' с ';
if (m = 0) and (w = 0) and (d = 0) and (h = 0) and (min = 0) and (sec = 0)
then Result := '0 c';
end;
Вроде как все нормально, но обнаружил проблему неправильного подсчета, если взять кол-во секунд примерно на 18 месяцев то при переводе данной функцией выйдет 17 месяцев 5 недель ... и при увеличении исходного числа недели,дни... будут расти превышая допустимые значения(7 дней, 24 часа...). Жду идеи :)

opel431
21-08-2012, 23:12
Можно попробовать не отсекать дробную часть (TRUNC), а округлять возвращаемое целое - ROUND(Int(...).
А, вообще, мне кажется, лучше измерять интервал используя TDateTime (1 сек = 1 / (24 * 60 * 60).

novashdima
22-08-2012, 00:16
округлять возвращаемое целое
не совсем понял, у меня возвращается вещественное число, если его округлить получится совсем не то, а целое из вещественного можно получить либо round либо trunc.
лучше измерять интервал используя TDateTime
нет, интервал лучше замерять TTimeStamp, но мне не интервал времени измерить надо, мне нужно перевести переменную с кол-вом секунд в удобочитаемое юзеру часы, дни....
ROUND(Int(...)
кстати такой структуры нет, единственный вариант - random(integer(...)), типа такого, тогда здесь ограничивается выбор чисел только целыми

opel431
22-08-2012, 02:24
кстати такой структуры нет »
Почему нет?
http://www.delphicode.org/math/Trunc_function.htm

Одна секунда в формате TDateTime равна: 1 / (24 * 60 * 60). Поэтому, если задан некоторый временной интервал Dt в формате TDateTime, то количество секунд в нём равно:
CntSec = Dt / ( 1 / (24 * 60 * 60) ) = Dt * (24 * 60 * 60).
Соответственно, можно функцию написать:Код Delphi
function GetSec(const aPeriod : TDateTime) : Int64;
const
K = 24 * 60 * 60;
begin
Result := Round( Int(aPeriod * K) );
end;
Источник - http://www.cyberforum.ru/delphi-beginners/thread325164.html

novashdima
22-08-2012, 04:04
Почему нет? »
Извиняюсь, совсем забыл про такую функцию, да и не удивительно, я ею не пользуюсь, вообще ненужная функция, обычно отбрасывают часть или округляют чтобы получить целое число, а эта функция вернет целое число, но в формате вещественного, если нужно вещественное число, то IntToFloat никто не отменял... ну да ладно.
насчет главного вопроса, пока сделал простым делением, но хотелось бы все таки понять, почему не работает этот вариант перевода. Кстати пробовал также написать более грамотно, борясь с возможными лагами и т.д., но главный баг (а может это и не баг) так и остался, вот доработанный код:
function ConvertTime(timeExt: Extended):string;
var m, w, d, h, min, sec: Int64;
begin
m := Trunc(Convert(timeExt, tuSeconds, tuMonths));
timeExt := timeExt - Trunc(Convert(m, tuMonths, tuSeconds));
w := Trunc(Convert(timeExt, tuSeconds, tuWeeks));
timeExt := timeExt - Trunc(Convert(w, tuWeeks, tuSeconds));
d := Trunc(Convert(timeExt, tuSeconds, tuDays));
timeExt := timeExt - Trunc(Convert(d, tuDays, tuSeconds));
h := Trunc(Convert(timeExt, tuSeconds, tuHours));
timeExt := timeExt - Trunc(Convert(h, tuHours, tuSeconds));
min := Trunc(Convert(timeExt, tuSeconds, tuMinutes));
sec := timeExt - Trunc(Convert(min, tuMinutes, tuSeconds));
if m <> 0 then Result := IntToStr(m) + ' мес ';
if w <> 0 then Result := Result + IntToStr(w) + ' нед ';
if d <> 0 then Result := Result + IntToStr(d) + ' д ';
if h <> 0 then Result := Result + IntToStr(h) + ' ч ';
if min <> 0 then Result := Result + IntToStr(min) + ' м ';
if sec <> 0 then Result := Result + IntToStr(sec) + ' с ';
if (m = 0) and (w = 0) and (d = 0) and (h = 0) and (min = 0) and (sec = 0)
then Result := '0 c';
end;

AlexVol
22-08-2012, 11:38
Вот еще пример конвертации секунд. Я правда остановился на днях, но мне больше и не надо было
function SecToTimeStr(Seconds : Integer) : String;
const
SecPerDay = 86400;
SecPerHour = 3600;
SecPerMinute = 60;

var
dd, ss, mm, hh: Cardinal;
str : String;
begin
str := '';
dd := Seconds div SecPerDay;
hh := (Seconds mod SecPerDay) div SecPerHour;
mm := ((Seconds mod SecPerDay) mod SecPerHour) div SecPerMinute;
ss := ((Seconds mod SecPerDay) mod SecPerHour) mod SecPerMinute;
str := Format('%2.2d:%2.2d:%2.2d',[hh,mm,ss]);
if dd>0 then
str := Format('%d дн ',[dd])+str;
result := str;
end;

novashdima
22-08-2012, 14:30
AlexVol, я тоже переделал код до обычного деления, у меня чуть попроще получилось, хотя кое какие упрощения мне подсказали)

function DivAndMod(var Value : Int64; Divider : Byte):Int64;
begin
Result := Value mod Divider;
Value := Value div Divider;
end;

function ConvertTime(m: Int64):string;
var m, w, d, h, min, sec: Int64;
begin
sec := DivAndMod(m, 60);
min := DivAndMod(m, 60);
h := DivAndMod(m, 24);
w := DivAndMod(m, 30);
d := DivAndMod(w, 7);
//остальные действия
end;

novashdima
24-08-2012, 03:22
SecPerDay = 86400; »
кстати в делфи существует константа SecsPerDay, которая равна вашим 86400, поэтому вводить новую не обязательно)

AlexVol
24-08-2012, 12:01
Но так как других нет, то для наглядности лучше забить свою. Много усилий это не займет.

novashdima
25-08-2012, 21:22
Много усилий это не займет. »
И это верно.




© OSzone.net 2001-2012