Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Конвертирование времени (http://forum.oszone.net/showthread.php?t=241042)

novashdima 21-08-2012 14:35 1973972

Конвертирование времени
 
Добрый день. Не так давно решил переписать участки с говнокодом в программе, до этого не было времени, а функции были не важные, сейчас переработал два куска кода, но после исправления второго нечаянно обнаружил проблему. Сама функция занимается переводом секунд в минуты, часы... казалось, что проще, оказалось и тут проблема есть. Привожу код:
Код:

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 1974315

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

novashdima 22-08-2012 00:16 1974357

Цитата:

округлять возвращаемое целое
не совсем понял, у меня возвращается вещественное число, если его округлить получится совсем не то, а целое из вещественного можно получить либо round либо trunc.
Цитата:

лучше измерять интервал используя TDateTime
нет, интервал лучше замерять TTimeStamp, но мне не интервал времени измерить надо, мне нужно перевести переменную с кол-вом секунд в удобочитаемое юзеру часы, дни....
Цитата:

ROUND(Int(...)
кстати такой структуры нет, единственный вариант - random(integer(...)), типа такого, тогда здесь ограничивается выбор чисел только целыми

opel431 22-08-2012 02:24 1974392

Цитата:

Цитата novashdima
кстати такой структуры нет »

Почему нет?
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-begi...ead325164.html

novashdima 22-08-2012 04:04 1974409

Цитата:

Цитата opel431
Почему нет? »

Извиняюсь, совсем забыл про такую функцию, да и не удивительно, я ею не пользуюсь, вообще ненужная функция, обычно отбрасывают часть или округляют чтобы получить целое число, а эта функция вернет целое число, но в формате вещественного, если нужно вещественное число, то 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 1974556

Вот еще пример конвертации секунд. Я правда остановился на днях, но мне больше и не надо было
Код:

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 1974660

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 1975931

Цитата:

Цитата AlexVol
SecPerDay = 86400; »

кстати в делфи существует константа SecsPerDay, которая равна вашим 86400, поэтому вводить новую не обязательно)

AlexVol 24-08-2012 12:01 1976083

Но так как других нет, то для наглядности лучше забить свою. Много усилий это не займет.

novashdima 25-08-2012 21:22 1976958

Цитата:

Цитата AlexVol
Много усилий это не займет. »

И это верно.


Время: 19:04.

Время: 19:04.
© OSzone.net 2001-