Большой Воронежский Форум
» Программирование>Как в Delphi дату и время посчиать в секундах.
THT 14:01 14.10.2006
Подскажите пожалуйста как в Delphi дату и время посчиать в секундах.
Например есть переменная типа ДатаВремя и мне нужно значение этой переменной записать в секундах в другую переменную типа Integer.

Заранее спасибо за понятные советы. [Ответ]
Ivan XXX 20:09 14.10.2006
хм... а как дату в секунды перевести? от какого момента секунды отщитывать будем? от рождества христова? [Ответ]
zeroserg 23:59 14.10.2006
имхо, интегера не хватит
зыЖ а математику кто отменял, на басме всё помнож и будет тебе счастие
[Ответ]
THT 13:58 15.10.2006
05.00.0000 12:30:35 посчитать в секундах
т.е 35 + 30*60 + 12*60*60 + 5*24*60*60.
Как это реализовать в Delphi? [Ответ]
ASSA 17:16 15.10.2006
Тип DateTime вроде как является даблом. целая часть- дни. дробная -доля суток. 0,5 это 12 часов дня. дальше сам дойдешь?
все на основе си-билдера. в дельфях по-моему то же самое.
[Ответ]
aerin 11:59 16.10.2006
В MSDN в описании функции RtlTimeToSecondsSince1970, доступной только начиная с 2000Prof и XP, есть описание алгоритма этих вычислений:

There is no single equivalent public function. To perform this task using public functions, use the following steps:

1. Call SystemTimeToFileTime to copy the system time to a FILETIME structure. Call GetSystemTime to get the current system time to pass to SystemTimeToFileTime.
2. Copy the contents of the FILETIME structure to a ULARGE_INTEGER structure.
3. Initialize a SYSTEMTIME structure with the date and time of the first second of January 1, 1970.
4. Call SystemTimeToFileTime, passing the SYSTEMTIME structure initialized in Step 3 to the call.
5. Copy the contents of the FILETIME structure returned by SystemTimeToFileTime in Step 4 to a second ULARGE_INTEGER. The copied value should be greater than or equal to the value copied in Step 2.
6. Subtract the 64-bit value in the ULARGE_INTEGER structure initialized in Step 2 from the 64-bit value of the ULARGE_INTEGER structure initialized in Step 5.

А дальше, по образу и подобию... [Ответ]
THT 13:19 16.10.2006
А для глупых нельзя как-нибудь попроще и поконкретнее. [Ответ]
aerin 13:27 16.10.2006
THT
Например? Что не устраивает в алгоритме от MS? [Ответ]
ХАРЧО 09:29 20.10.2006
Мне так кажется, что нужно просто применить функцию:
function DateTimeToFileDate(DateTime: TDateTime): Integer; [Ответ]
aerin 10:12 20.10.2006
ХАРЧО
Я не знаю, что делает функция DateTimeToFileDate, но, судя по названию, у меня складывается впечатление, что это обертка над SystemTimeToFileTime, странно только, что у вас она возвращает Integer, а в win32 файловое время принято отсчитывать от 01.01.1601(UTC) с 100-наносекундным интервалом.
Но не суть, расскажите как, пользуясь вашей замечательной функцией вы решите задачу про "05.00.0000 12:30:35", поставленную автором в посте #4? [Ответ]
ХАРЧО 10:33 20.10.2006
aerin, любите WinAPI? Чтож похвально. Но в этом случае вопрос можно решить и чисто дельфивскими путями (которые, естественно опираюстся на WinAPI, но имеют, имхо, несколько болле удобный интерфейс).
Про вопрос #4 скажу следующее: попробуйте функцию:
function StrToDateTime(const S: string; const FormatSettings: TFormatSettings): TDateTime;
Таким образом вы из строки получите тип TDateTime, как это спрашивалось в вопросе #1. А затем вышеуказанным путем.
P.S. Я далек от мысли, что изложенный мной способ наиболее простой и быстрый, это всего лишь мое мнение.... [Ответ]
gloomdemon 11:30 20.10.2006
aerin,
видимо Вы не особо знакомы с delphi, просто тогда ,ы знали что в делфи на каждый чих не надо лезть в мсдн и искать решение, там в большинстве случаем уже всё под рукой. То что предложил ХАРЧО верно.

Всё будет очень просто DateTimeToFileDate(StrToDateTime('5.05.2006 7:42:11')); Это касательно поста #1.
Как написано в хелпе DateTimeToFileDate преобразует TDateTime object to an OS timestamp. А то что там 4 байта возращается, ну так это не только проблема Delphi, time_t в linux тоже 4 байта =) Для времени в промежутке 1980 - 2099 (это в делфи хелп так, по други источникам до 2190)хватает, а там ещё одна "проблема 2000"

ime_t time(time_t *tloc);
DESCRIPTION
The time() function returns the value of time in seconds
since 00:00:00 UTC, January 1, 1970.

А касательно поста #4 то наверное дату 05.00.0000 надо от 0000 года и отсчитывать, таких функций ещё наверное нет
[Ответ]
ХАРЧО 11:37 20.10.2006
Ой, бл@! Я облажался! Как отсчитывать от

Сообщение от THT:
05.00.0000

нулевого года меня еще в ПТУ не научили.... [Ответ]
gloomdemon 11:50 20.10.2006
ХАРЧО, да ни чё. Если брать алгоритм из мсдн то вообще в минуса уйдёшь. Будет модная дата =)

ЗЫ
А вообще самое модное это на js:

<script language="JavaScript"><!--
var aDate = 925241310748; // miliseconds Since 1970;

theDate = new Date(aDate);
dd = theDate.getDate();
mm = theDate.getMonth()+1; // 0 based
yy = theDate.getYear();
if (yy < 1000) yy +=1900; // Y2K fix

alert (dd+'/'+mm+'/'+yy);
//--></script>

даже Y2K fix есть! [Ответ]
ХАРЧО 11:56 20.10.2006
gloomdemon, весело! Можно на форму кинуть компонент TWebBrowser, в нем открыть этот немного модифицированный код, чтобы он вызывал одно из событий компонента и смело передавать это в Int64.
ЯплакалЪ! [Ответ]
aerin 13:26 20.10.2006

Сообщение от :
__int64 i64GetSecsFromDate( SYSTEMTIME* sm )
{
__int64 temp = 0; // итоговое количество секунд
// Список дней в первых одиннадцати месяцах:
int months[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 };

// Вычисляем число секунд, содержащихся в числе полных лет:
temp += 60 * 60 * 24 * ( 365 * (__int64)sm->wYear + (__int64)(sm->wYear / 4 ) );

// Добавляем секунды прошедших в текущем году месяцев:
for( int i = 0; i < (sm->wMonth - 1); i++ )
{
temp += 60 * 60 * 24 * (__int64)months[i];
}

// Дальше все просто:
temp += 60 * 60 * 24 * (__int64)sm->wDay;
temp += 60 * 60 * (__int64)sm->wHour;
temp += 60 * (__int64)sm->wMinute;
temp += (__int64)sm->wSecond;

return temp;
}

ЗЫ. Результат вызова на датах после 1970 года совпадает с результатом вызова RtlTimeToSecondsSince1970, что подтверждает правильность алгоритма.
ЗЫЫ. На отрицательных датах будет работать неверно.
ЗЫЫЫ. На Delphi, извините, религия и руководство писать не позволяют.
ЗЫЫЫЫ. Если надо, могу доработать и для отрицательных дат.
[Ответ]
aerin 14:51 20.10.2006
Тут меня поправили в двух местах:
1. Если целевой год високосный, то нужно изменить для этого года продолжительность февраля с 28 до 29 дней.
2. После реформы 1582 года високосными из годов, делящихся на 100, стали считаться только те из них, которые к тому же делились на 400.
Таким образом окончательная версия функции принимает вид:

Сообщение от :
__int64 i64GetSecsFromDate( SYSTEMTIME* sm )
{
__int64 temp = 0; // итоговое количество секунд
// Список дней в первых одиннадцати месяцах:
int months[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 };

// Исправление для високосных лет после 1582 года.
// ( т.н. реформа календаря Григория XIII )
int subLeapYears = 0;
int addLeapYears = 0;
if( 1600 < sm->wYear )
{
subLeapYears = ( sm->wYear - 1600 ) / 100;
addLeapYears = subLeapYears / 4;
// Исправление для дат после 28.02 в високосном году:
if( 0 == sm->wYear % 100 )
{
if( 0 == sm->wYear % 400 )
{
months[1] = 29;
}
}
else
{
if( 0 == sm->wYear % 4 )
months[1] = 29;
}
}
else
{
// Исправление для дат после 28.02 в високосном году:
if( 0 == sm->wYear % 4 )
months[1] = 29;
}

// Вычисляем число секунд, содержащихся в числе полных лет:
temp += 60 * 60 * 24 * ( 365 * (__int64)sm->wYear + (__int64)(sm->wYear / 4) -
subLeapYears + addLeapYears );

// Добавляем секунды прошедших в текщем году месяцев:
for( int i = 0; i < (sm->wMonth - 1); i++ )
{
temp += 60 * 60 * 24 * (__int64)months[i];
}

// Дальше все просто:
temp += 60 * 60 * 24 * (__int64)sm->wDay;
temp += 60 * 60 * (__int64)sm->wHour;
temp += 60 * (__int64)sm->wMinute;
temp += (__int64)sm->wSecond;

return temp;
}

[Ответ]
gloomdemon 17:02 20.10.2006
aerin, эх и чего люди не придумают что бы boost использовать раз религия на делфи не позволяет.

/* This example demonstrates the use of the time zone database and
* local time to calculate the number of seconds since the UTC
* time_t epoch 1970-01-01 00:00:00. Note that the selected timezone
* could be any timezone supported in the time zone database file which
* can be modified and updated as needed by the user.
*
* To solve this problem the following steps are required:
* 1) Get a timezone from the tz database for the local time
* 2) Construct a local time using the timezone
* 3) Construct a posix_time:time for the time_t epoch time
* 4) Convert the local_time to utc and subtract the epoch time
*
*/

#include "boost/date_time/local_time/local_time.hpp"
#include <iostream>

int main()
{
using namespace boost::gregorian;
using namespace boost::local_time;
using namespace boost:
osix_time;

tz_database tz_db;
try {
tz_db.load_from_file("../data/date_time_zonespec.csv");
}catch(data_not_accessible dna) {
std::cerr << "Error with time zone data file: " << dna.what() << std::endl;
exit(EXIT_FAILURE);
}catch(bad_field_count bfc) {
std::cerr << "Error with time zone data file: " << bfc.what() << std::endl;
exit(EXIT_FAILURE);
}

time_zone_ptr nyc_tz = tz_db.time_zone_from_region("America/New_York");
date in_date(2004,10,04);
time_duration td(12,14,32);
// construct with local time value
// create not-a-date-time if invalid (eg: in dst transition)
local_date_time nyc_time(in_date,
td,
nyc_tz,
local_date_time::NOT_DATE_TIME_ON_ERROR);

std::cout << nyc_time << std::endl;

ptime time_t_epoch(date(1970,1,1));
std::cout << time_t_epoch << std::endl;

// first convert nyc_time to utc via the utc_time()
// call and subtract the ptime.
time_duration diff = nyc_time.utc_time() - time_t_epoch;

//Expected 1096906472
std::cout << "Seconds diff: " << diff.total_seconds() << std::endl;

}
[Ответ]
aerin 17:15 20.10.2006
gloomdemon
But my example demonstres how to calculate the number of seconds sinse 0.0.0 00:00:00 by one iteration. Андестенд? [Ответ]
mikе 17:40 20.10.2006

Сообщение от :
unit unix_utils;
interface
implementation
const
// Sets UnixStartDate to TDateTime of 01/01/1970
UnixStartDate: TDateTime = 25569.0;
function DateTimeToUnix(ConvDate: TDateTime): Longint;
begin
//example: DateTimeToUnix(now);
Result := Round((ConvDate - UnixStartDate) * 86400);
end;
function UnixToDateTime(USec: Longint): TDateTime;
begin
//Example: UnixToDateTime(1003187418);
Result := (Usec / 86400) + UnixStartDate;
end;
end.

делает unix-timestamp [Ответ]
aerin 17:47 20.10.2006
mikе
Те же яйца. А до 1970 года? См. пост №4. [Ответ]
mikе 17:52 20.10.2006
выдаст отрицательный. в РНР, к примеру, сие замечательно работает (правда, только под никсами — под виндой не катит) [Ответ]
gloomdemon 18:25 20.10.2006

Сообщение от aerin:
But my example demonstres how to calculate the number of seconds sinse 0.0.0 00:00:00 by one iteration. Андестенд?

Use power Luke!
time_duration diff = nyc_time.utc_time() - time_t_epoch; --> time_duration diff = nyc_time.utc_time();

А вообще прикольно =) Кто на асме напишет? [Ответ]
ХАРЧО 18:28 20.10.2006
Ух как вас всех торкнуло-то, двоих в C/C++ заносит, видел пост с кодами на JavaScript, один человек с юниксовыми timestamp'aми работать изволит, еще кого-то на асм потянуло.... Аффтар темы уже давно над нами тихо посмеивается, скажет: "Давайте, ребята, старайтесь, напишите искуственный интелект для решения моей задачи...". По-моему мы уже решили поставленную задачу... Закрывайте тему, а то флеймить начну... [Ответ]
Вверх