Операции с дати?
21 отговора
1581 прегледа
Операции с дати?
Тюх да му се не види - трябват ми методи за работа с дати - по точно метод който ми дава разлика между 2 дати - в години или месеци (за дни е лесно). Тези които ги има в SysUtils - не ми вършат работа защото ползват приближения - а на мен ми трябва абсолютна точност.
Ако някой е срещал подобни неща и нета нека сподели ;-)))
---

Ако някой е срещал подобни неща и нета нека сподели ;-)))
---
Филосфстване :)
1. Сегашните процесори, които са много бързи в аритметиката, са подходящи за определяне на разликата посредством събиране: към по-малката дата започваш да прибавяш години, докато стане по-голяма от голямата дата, връщаш едно назад (може и по-умно), след това добавяш месеци... и накрая - дни.
за период от 100 години максимумът е 100+11+30 итерации - нищо работа :)
(е, понякога трябва да проверяваш годината дали е високосна)
2. За мои нужди смятам такива периоди, като приемам, че един месец има 365.25/12 дни (~30.5 дни). До сега не са ме хванали :)
за период от 100 години максимумът е 100+11+30 итерации - нищо работа :)
(е, понякога трябва да проверяваш годината дали е високосна)
2. За мои нужди смятам такива периоди, като приемам, че един месец има 365.25/12 дни (~30.5 дни). До сега не са ме хванали :)
Ъмм...
тия от DateUtils също ли не ти вършат работа? 
There are three determined states the cat could be in: Alive, Dead, and Bloody Furious.
There are three determined states the cat could be in: Alive, Dead, and Bloody Furious.
Re: Ъмм...
Ако погледнеш точка 2 от горния пост - ще разбереш, защо DateUtils не ми върши работа
Там дните в годината се смятат нещо като 365.25 не помня каква беше константата - което разбира се води до грешки.
---

Там дните в годината се смятат нещо като 365.25 не помня каква беше константата - което разбира се води до грешки.
---
Re: Филосфстване :)
По точка 1 - разбира се, че така ще го направя ако нищо друго не намеря - ама мисля си че някъде може да има оптимизиран метод за това - особенно за месеците ще е грозно и бавно - ако става дума за 5 или 10 години - не че няма да го врътне за под 1 секунда - ама представи си този алгоритъм вкаран в друг по-сложен и изпълняващ се при калкулация на всеки ред в БД.
За 2 - за съжаление аз съм безкомпромисен в това отношение - вярно, че грешката може да се появи веднъж на 1000 примерно - но е грешка от която някой ще загуби пари - за това не мога да си го позволя.
---

За 2 - за съжаление аз съм безкомпромисен в това отношение - вярно, че грешката може да се появи веднъж на 1000 примерно - но е грешка от която някой ще загуби пари - за това не мога да си го позволя.
---
Re: Филосфстване :)
Това съм си написал за разлика в години, месеци, дни, часове ...
uses DateUtils, Math, SysUtils;
procedure DecodeDateTimeDif(DateTime1,DateTime2:TDateTime;
var YY,MM,DD,HH,MN,SS,MS:integer);
var
YY1,YY2,MM1,MM2,DD1,DD2,HH1,HH2,MN1,MN2,SS1,SS2,MS1,MS2:word;
DT:TDateTime;
begin
If DateTime1>DateTime2
then begin
DecodeDateTime(DateTime2,YY1,MM1,DD1,HH1,MN1,SS1,MS1);
DecodeDateTime(DateTime1,YY2,MM2,DD2,HH2,MN2,SS2,MS2);
DT:=DateTime1;
end
else begin
DecodeDateTime(DateTime1,YY1,MM1,DD1,HH1,MN1,SS1,MS1);
DecodeDateTime(DateTime2,YY2,MM2,DD2,HH2,MN2,SS2,MS2);
DT:=DateTime2;
end;
YY:=YY2-YY1;
MM:=MM2-MM1;
DD:=DD2-DD1;
HH:=HH2-HH1;
MN:=MN2-MN1;
SS:=SS2-SS1;
MS:=MS2-MS1;
If MS<0 then begin SS:=SS-1;MS:=MS+1000;end;
If SS<0 then begin MN:=MN-1;SS:=SS+60;end;
If MN<0 then begin HH:=HH-1;MN:=MN+60;end;
If HH<0 then begin DD:=DD-1;HH:=HH+24;end;
If DD<0 then begin MM:=MM-1;DD:=DD+DaysInMonth(IncMonth(DT,-1));end;
If MM<0 then begin YY:=YY-1;MM:=MM+12;end;
end;
end.
uses DateUtils, Math, SysUtils;
procedure DecodeDateTimeDif(DateTime1,DateTime2:TDateTime;
var YY,MM,DD,HH,MN,SS,MS:integer);
var
YY1,YY2,MM1,MM2,DD1,DD2,HH1,HH2,MN1,MN2,SS1,SS2,MS1,MS2:word;
DT:TDateTime;
begin
If DateTime1>DateTime2
then begin
DecodeDateTime(DateTime2,YY1,MM1,DD1,HH1,MN1,SS1,MS1);
DecodeDateTime(DateTime1,YY2,MM2,DD2,HH2,MN2,SS2,MS2);
DT:=DateTime1;
end
else begin
DecodeDateTime(DateTime1,YY1,MM1,DD1,HH1,MN1,SS1,MS1);
DecodeDateTime(DateTime2,YY2,MM2,DD2,HH2,MN2,SS2,MS2);
DT:=DateTime2;
end;
YY:=YY2-YY1;
MM:=MM2-MM1;
DD:=DD2-DD1;
HH:=HH2-HH1;
MN:=MN2-MN1;
SS:=SS2-SS1;
MS:=MS2-MS1;
If MS<0 then begin SS:=SS-1;MS:=MS+1000;end;
If SS<0 then begin MN:=MN-1;SS:=SS+60;end;
If MN<0 then begin HH:=HH-1;MN:=MN+60;end;
If HH<0 then begin DD:=DD-1;HH:=HH+24;end;
If DD<0 then begin MM:=MM-1;DD:=DD+DaysInMonth(IncMonth(DT,-1));end;
If MM<0 then begin YY:=YY-1;MM:=MM+12;end;
end;
end.
Не съм съвсем съгласен за т.1
За каква секунда става въпрос (истинските програмисти оптимизират наносекундите :)?
За интервали от около 10 години алгоритъма (+- един порядък) няма да изисква повече от 500 събирания/изваждания.
Ако работиш с цялата част на датите (а след това доуточниш с дробните им части - без загуба на точност) - това ще са 500 целочислени събирания (най-вероятно в кеша на процесора) - стават за 0 време.
Може би и теоретично това да е най-бързия алгоритъм.
Но не е красив :) - съгласен съм.
Разбира се, няма да е неочаквано, ако някой във форума предложи по-добра идея.
(Да не смяташ лихви? - да ти изпратя една баноква сметка, където да пращаш остатъците от закръглянето?)
ПП
Е, аз бих ползвал предложеното от NDew (за да не се занимавам цял ден с тази играчка)
Но процедурата на NDew изглежда и навярно е много добра, но ако искаш да си прецизен, ще трябва да сравниш времето за изпълнение (а то и за двата алгоритъма зависи от данните:). Аз не съм сигурен, че тя е по-ефективна, въпреки, че виканите подпрограми ползват маса константи и таблици. - Все пак всеки call с толкова много параметри е в пъти по-бавен от едно целочислено събиране)

За интервали от около 10 години алгоритъма (+- един порядък) няма да изисква повече от 500 събирания/изваждания.
Ако работиш с цялата част на датите (а след това доуточниш с дробните им части - без загуба на точност) - това ще са 500 целочислени събирания (най-вероятно в кеша на процесора) - стават за 0 време.
Може би и теоретично това да е най-бързия алгоритъм.
Но не е красив :) - съгласен съм.
Разбира се, няма да е неочаквано, ако някой във форума предложи по-добра идея.
(Да не смяташ лихви? - да ти изпратя една баноква сметка, където да пращаш остатъците от закръглянето?)
ПП
Е, аз бих ползвал предложеното от NDew (за да не се занимавам цял ден с тази играчка)
Но процедурата на NDew изглежда и навярно е много добра, но ако искаш да си прецизен, ще трябва да сравниш времето за изпълнение (а то и за двата алгоритъма зависи от данните:). Аз не съм сигурен, че тя е по-ефективна, въпреки, че виканите подпрограми ползват маса константи и таблици. - Все пак всеки call с толкова много параметри е в пъти по-бавен от едно целочислено събиране)
Редактирано от NikB на
Re: Филосфстване :)
В отговор на:За мои нужди смятам такива периоди, като приемам, че един месец има 365.25/12 дни (~30.5 дни). До сега не са ме хванали :)
За твои нужди можеш да го смяташ така, като те устройва, но за нуждите на клиентите си трябва да се съобразяваш с правилата, които са приети за съответната предметна област
Напр. банкерите по закон смятат годината за 360-дневна, а месеца за 30-дневен.
Едни наемодатели пък искаха от програмата да не смята първите три месеца от наема, ако .... и да ги смята ако ...
Ами какво ще кажеш за...
Delphi Fundamentals
Това горе е урл, ама новия дизайн на клубовете е крап...
There are three determined states the cat could be in: Alive, Dead, and Bloody Furious.
Това горе е урл, ама новия дизайн на клубовете е крап...
There are three determined states the cat could be in: Alive, Dead, and Bloody Furious.
Re: Не съм съвсем съгласен за т.1
Това като го разказах на моя P4 нам колко си GHz и той умря от смях. Вика "къде е това алгоритъмче, да го изпапкам за закуска".
Сега сериозно - ако искаш да сравняваш ефективността на алгоритми, имаше навремето една книжка от Т. М. Смит "Принципи и методи на програмирането с Паскал". Та в нея се описваха основните структури от данни и алгоритмите за работа с тях, вкл. фундаменталните "търсене", "сортиране" и т.н. За всеки от тях автора извеждаше ефективността като общ брой операции (итерации, сравнения и др.) в средния случай в зав. от входните данни. Обобщението от цялата работа беше, че най-ефективния алгоритъм си остава линейния (без вложени цикли), а това какъв обем данни се подава (или в нашия случай колко години, месеци и дни ще се броят) е все тая и няма нищо общо с ефективността. Единственото условие е алгоритъма да работи точно и без грешки, спрямо заданието.
И двата предложени метода са с теоретична ефективност O(N). Ако съответните подпрограми от алгоритъма на NDeu са оптимални (линейни в най-добрия случай), то неговия алгоритъм е оптимален по отношение на поставеното условие за точност. Твоя, макар и малко по-бърз спрямо същите входни данни, не се класира заради грешки в изчисленията.
Mixy
Сега сериозно - ако искаш да сравняваш ефективността на алгоритми, имаше навремето една книжка от Т. М. Смит "Принципи и методи на програмирането с Паскал". Та в нея се описваха основните структури от данни и алгоритмите за работа с тях, вкл. фундаменталните "търсене", "сортиране" и т.н. За всеки от тях автора извеждаше ефективността като общ брой операции (итерации, сравнения и др.) в средния случай в зав. от входните данни. Обобщението от цялата работа беше, че най-ефективния алгоритъм си остава линейния (без вложени цикли), а това какъв обем данни се подава (или в нашия случай колко години, месеци и дни ще се броят) е все тая и няма нищо общо с ефективността. Единственото условие е алгоритъма да работи точно и без грешки, спрямо заданието.
И двата предложени метода са с теоретична ефективност O(N). Ако съответните подпрограми от алгоритъма на NDeu са оптимални (линейни в най-добрия случай), то неговия алгоритъм е оптимален по отношение на поставеното условие за точност. Твоя, макар и малко по-бърз спрямо същите входни данни, не се класира заради грешки в изчисленията.
Mixy
Редактирано от Mixy на
Май нещо не си разбрал :)
1. В алгоритъма, на когото обсъждаме производителността (т.2.) няма грешки (и е абсолютно точен), по простата причина, че не е описан в подробности :)
(моля, преди да си категоричен, чети внимателно).
2. Линейните алгоритми могат да се различават по много параметри:
- ползване или не на плаваща запетая;
- брой влизания в подпрограми;
- цикли
...
- и не на последно място - комбинацията като количествено отношението на изброеното до тук в различните алгоритми.
В тази връзка още преди да постна предното, си направих труда да погледна преобразуването на DateTime в година, месец, .... - погледни го и ти и ще видиш, че няма значение дали го правиш на P4 или на 4004 - все тая.
(На снимката изглеждаш младо момче - та 4004 е първия истински процесор, а sci-fi научна фантастика ли е?).
В заключение - ако имаш дебъг средство за определяне на времето за изпълнение на програмата (аз няма лицензирано такова, а изтече периода на ползване) и ако ти се занимава - можеш да провериш.
Късмет!
(моля, преди да си категоричен, чети внимателно).
2. Линейните алгоритми могат да се различават по много параметри:
- ползване или не на плаваща запетая;
- брой влизания в подпрограми;
- цикли
...
- и не на последно място - комбинацията като количествено отношението на изброеното до тук в различните алгоритми.
В тази връзка още преди да постна предното, си направих труда да погледна преобразуването на DateTime в година, месец, .... - погледни го и ти и ще видиш, че няма значение дали го правиш на P4 или на 4004 - все тая.
(На снимката изглеждаш младо момче - та 4004 е първия истински процесор, а sci-fi научна фантастика ли е?).
В заключение - ако имаш дебъг средство за определяне на времето за изпълнение на програмата (аз няма лицензирано такова, а изтече периода на ползване) и ако ти се занимава - можеш да провериш.
Късмет!
Извън кокретната тема- ПИТАМ за DelphiFundamentals
Ползваш ли сокет компонентите? Моля, сподели опит!
Тц...
ползвам си инди-то засега ми е достатъчно 
There are three determined states the cat could be in: Alive, Dead, and Bloody Furious.
There are three determined states the cat could be in: Alive, Dead, and Bloody Furious.
Re: Напълно е възможно :)
ОК, приемам критиката!
По т.1 си прав, говорех наизуст.
По т.2 може да се поспори, но ще задълбаем. Както и да е, само отбелязвам, че скорост на изпълнение и ефективност са две различни понятия по отношение на алгоритмите.
В собствена защита ще изтъкна, че ме събудиха рано, не бях пил кафе още и собствения ми процесор/мозък даваше отклонения от нормата.
> На снимката изглеждаш младо момче ... - не само изглеждам, а и се чувствам така!
> ... та 4004 е първия истински процесор ... - знам, въпреки, че когато той е бил пуснат на пазара, още не съм бил планиран.
> ... а sci-fi научна фантастика ли е? - да.
Мир?
------
[OFF] А твойта снимка де е, че и аз съм любопитен?
Mixy
По т.1 си прав, говорех наизуст.
По т.2 може да се поспори, но ще задълбаем. Както и да е, само отбелязвам, че скорост на изпълнение и ефективност са две различни понятия по отношение на алгоритмите.
В собствена защита ще изтъкна, че ме събудиха рано, не бях пил кафе още и собствения ми процесор/мозък даваше отклонения от нормата.
> На снимката изглеждаш младо момче ... - не само изглеждам, а и се чувствам така!
> ... та 4004 е първия истински процесор ... - знам, въпреки, че когато той е бил пуснат на пазара, още не съм бил планиран.
> ... а sci-fi научна фантастика ли е? - да.
Мир?
------
[OFF] А твойта снимка де е, че и аз съм любопитен?
Mixy
Толкова заядливо ли съм писал :)
Мислех, че съм писал умерено, но явно като не ми върви работата се изнервям.
Въпреки, че в такива случеи поне с кеф се мотая по форумите :)
Късмет!
Ето ти едно решение, което бачка!
Значи, под LINUX има една много хубава функцийка gettimeofday(), която я няма в Windows.
Няма ли казах ?! Глупости - има я. Намерих я в сорсовете на Microsoft-ските библиотеки. Дори мога да ви copy/paste-на малко от коментарите, към сорсовете които пиша с коментар на един от бисерите които имаше в оригиналния майкрософтски сорс (аз пиша коментарите в сорсовете на английски, щото на български трудно ме разбират, а и не се справят с кирилицата):
/*
FILETIME is based on the win32 epoch which starts 1 Jan 1601, 00:00:00 ?! Actually as seen the code they use a call to gettimeofday() to get the UNIX time and convert it to FILETIME, but suppress the function use and definition, so we're going back here and return it to a UNIX time according to the formula they use.
*/
Виждате ли UNIX-ката епоха старира от 1 януари 1970, но Windows е далеч по първичен - 1 Jan 1601.
Та извода е следният. Използвай FILETIME и GetSystemTimeAsFileTime(). Тествано е бачка супер - аз го ползвам да засичам времеви интервали за MySQL заявки.
Малко от описанието на FILETIME:
The FILETIME structure is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).
Това е от MSDN-а. Тук няма тъпия коментар от Windows-кия сорс за win32 епохата (ако някой се чуди откъде я измислиха тази абсурдна стартова дата).
Разликата е, че FILETIME ти връща резултата в милисекунди (хилядни) а gettimeofday в микросекунди (милионни). Това за LINUX/Windows API-та и разлики.
Но можеш доста добре да я ползваш. Разбира се малко обработка трябва да извадиш няколко милиарда милисекунди от Майкрософтската (?!) епоха, докато го напаснеш до UNIX-ката епоха, ако ти трябва, ако не - имаш 64 битов интеджър с точност до милисекундата, съдържащо време от турско време при това в милисекунди !!!
Майкрософт! Попрекалили сте с уискито ...
Няма ли казах ?! Глупости - има я. Намерих я в сорсовете на Microsoft-ските библиотеки. Дори мога да ви copy/paste-на малко от коментарите, към сорсовете които пиша с коментар на един от бисерите които имаше в оригиналния майкрософтски сорс (аз пиша коментарите в сорсовете на английски, щото на български трудно ме разбират, а и не се справят с кирилицата):
/*
FILETIME is based on the win32 epoch which starts 1 Jan 1601, 00:00:00 ?! Actually as seen the code they use a call to gettimeofday() to get the UNIX time and convert it to FILETIME, but suppress the function use and definition, so we're going back here and return it to a UNIX time according to the formula they use.
*/
Виждате ли UNIX-ката епоха старира от 1 януари 1970, но Windows е далеч по първичен - 1 Jan 1601.
Та извода е следният. Използвай FILETIME и GetSystemTimeAsFileTime(). Тествано е бачка супер - аз го ползвам да засичам времеви интервали за MySQL заявки.
Малко от описанието на FILETIME:
The FILETIME structure is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).
Това е от MSDN-а. Тук няма тъпия коментар от Windows-кия сорс за win32 епохата (ако някой се чуди откъде я измислиха тази абсурдна стартова дата).
Разликата е, че FILETIME ти връща резултата в милисекунди (хилядни) а gettimeofday в микросекунди (милионни). Това за LINUX/Windows API-та и разлики.
Но можеш доста добре да я ползваш. Разбира се малко обработка трябва да извадиш няколко милиарда милисекунди от Майкрософтската (?!) епоха, докато го напаснеш до UNIX-ката епоха, ако ти трябва, ако не - имаш 64 битов интеджър с точност до милисекундата, съдържащо време от турско време при това в милисекунди !!!
Майкрософт! Попрекалили сте с уискито ...
А и още нещо ...
Мисля че и Borland-ския TDateTime е базиран на FILETIME. Ако не е, май беше на нещо друго Windows-ко, но каквото и да е в Windows API ще намериш конвертиране от едното в другото. Майкрософт много си обичат техните типове данни и предоставят в API-то си достатъчно много, така че да ги заобичат всички :)
10х
Мерси - това ще да е - от грипа нещо не мога да мисля читаво - по точно си мислех за обикновено изваждане ама ми се сториха доста проверките - е не че ги няма ама ме мързеше да мисля.
Между другото намерих нещо ама е платено - ако някой му се дават пари - има доста фунции [линк]
---

Между другото намерих нещо ама е платено - ако някой му се дават пари - има доста фунции [линк]
---
Re: А и още нещо ...
Значи има разлика - TDateTime e Double до колкото помня. Разликата идва от различното представяне на часовете и секундите май. Има си функции за прекодиране, само че за едно такова изваждане не си струва - още повече, че може би начина на калкулация сигурно е подобен (разбирай оптимизиран като скорост ама работещ с определена грешка)
0 12/30/1899 12:00 am
2.75 1/1/1900 6:00 pm
-1.25 12/29/1899 6:00 am
35065 1/1/1996 12:00 am
---

0 12/30/1899 12:00 am
2.75 1/1/1900 6:00 pm
-1.25 12/29/1899 6:00 am
35065 1/1/1996 12:00 am
---
Re: Не, бе ... :)
Просто не сме се нацелили на кеф.
Карай да е весело. Късмет и на теб!
Mixy
Карай да е весело. Късмет и на теб!
Mixy