Операции с дати?

21 отговора 1581 прегледа
#1

Операции с дати?

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

---
Отговор
в отговор на PhantomAS #2

Филосфстване :)

1. Сегашните процесори, които са много бързи в аритметиката, са подходящи за определяне на разликата посредством събиране: към по-малката дата започваш да прибавяш години, докато стане по-голяма от голямата дата, връщаш едно назад (може и по-умно), след това добавяш месеци... и накрая - дни.
за период от 100 години максимумът е 100+11+30 итерации - нищо работа :)
(е, понякога трябва да проверяваш годината дали е високосна)

2. За мои нужди смятам такива периоди, като приемам, че един месец има 365.25/12 дни (~30.5 дни). До сега не са ме хванали :)

Отговор
в отговор на PhantomAS #3

Ъмм...

тия от DateUtils също ли не ти вършат работа?

There are three determined states the cat could be in: Alive, Dead, and Bloody Furious.
Отговор
в отговор на Koтapakът нa Шpьoдинrep #4

Re: Ъмм...

Ако погледнеш точка 2 от горния пост - ще разбереш, защо DateUtils не ми върши работа
Там дните в годината се смятат нещо като 365.25 не помня каква беше константата - което разбира се води до грешки.

---
Отговор
в отговор на NikB #5

Re: Филосфстване :)

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

---
Отговор
в отговор на PhantomAS #6

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.

Отговор
в отговор на PhantomAS #7

Не съм съвсем съгласен за т.1

За каква секунда става въпрос (истинските програмисти оптимизират наносекундите :)?
За интервали от около 10 години алгоритъма (+- един порядък) няма да изисква повече от 500 събирания/изваждания.
Ако работиш с цялата част на датите (а след това доуточниш с дробните им части - без загуба на точност) - това ще са 500 целочислени събирания (най-вероятно в кеша на процесора) - стават за 0 време.
Може би и теоретично това да е най-бързия алгоритъм.
Но не е красив :) - съгласен съм.
Разбира се, няма да е неочаквано, ако някой във форума предложи по-добра идея.
(Да не смяташ лихви? - да ти изпратя една баноква сметка, където да пращаш остатъците от закръглянето?)

ПП
Е, аз бих ползвал предложеното от NDew (за да не се занимавам цял ден с тази играчка)
Но процедурата на NDew изглежда и навярно е много добра, но ако искаш да си прецизен, ще трябва да сравниш времето за изпълнение (а то и за двата алгоритъма зависи от данните:). Аз не съм сигурен, че тя е по-ефективна, въпреки, че виканите подпрограми ползват маса константи и таблици. - Все пак всеки call с толкова много параметри е в пъти по-бавен от едно целочислено събиране)

Редактирано от NikB на

Отговор
в отговор на NikB #8

Re: Филосфстване :)

В отговор на:

За мои нужди смятам такива периоди, като приемам, че един месец има 365.25/12 дни (~30.5 дни). До сега не са ме хванали :)



За твои нужди можеш да го смяташ така, като те устройва, но за нуждите на клиентите си трябва да се съобразяваш с правилата, които са приети за съответната предметна област
Напр. банкерите по закон смятат годината за 360-дневна, а месеца за 30-дневен.
Едни наемодатели пък искаха от програмата да не смята първите три месеца от наема, ако .... и да ги смята ако ...

Отговор
в отговор на PhantomAS #9

Ами какво ще кажеш за...

Delphi Fundamentals

Това горе е урл, ама новия дизайн на клубовете е крап...

There are three determined states the cat could be in: Alive, Dead, and Bloody Furious.
Отговор
в отговор на NikB #10

Re: Не съм съвсем съгласен за т.1

Това като го разказах на моя P4 нам колко си GHz и той умря от смях. Вика "къде е това алгоритъмче, да го изпапкам за закуска".

Сега сериозно - ако искаш да сравняваш ефективността на алгоритми, имаше навремето една книжка от Т. М. Смит "Принципи и методи на програмирането с Паскал". Та в нея се описваха основните структури от данни и алгоритмите за работа с тях, вкл. фундаменталните "търсене", "сортиране" и т.н. За всеки от тях автора извеждаше ефективността като общ брой операции (итерации, сравнения и др.) в средния случай в зав. от входните данни. Обобщението от цялата работа беше, че най-ефективния алгоритъм си остава линейния (без вложени цикли), а това какъв обем данни се подава (или в нашия случай колко години, месеци и дни ще се броят) е все тая и няма нищо общо с ефективността. Единственото условие е алгоритъма да работи точно и без грешки, спрямо заданието.

И двата предложени метода са с теоретична ефективност O(N). Ако съответните подпрограми от алгоритъма на NDeu са оптимални (линейни в най-добрия случай), то неговия алгоритъм е оптимален по отношение на поставеното условие за точност. Твоя, макар и малко по-бърз спрямо същите входни данни, не се класира заради грешки в изчисленията.

Mixy

Редактирано от Mixy на

Отговор
в отговор на Mixy #11

Май нещо не си разбрал :)

1. В алгоритъма, на когото обсъждаме производителността (т.2.) няма грешки (и е абсолютно точен), по простата причина, че не е описан в подробности :)
(моля, преди да си категоричен, чети внимателно).
2. Линейните алгоритми могат да се различават по много параметри:
- ползване или не на плаваща запетая;
- брой влизания в подпрограми;
- цикли
...
- и не на последно място - комбинацията като количествено отношението на изброеното до тук в различните алгоритми.
В тази връзка още преди да постна предното, си направих труда да погледна преобразуването на DateTime в година, месец, .... - погледни го и ти и ще видиш, че няма значение дали го правиш на P4 или на 4004 - все тая.
(На снимката изглеждаш младо момче - та 4004 е първия истински процесор, а sci-fi научна фантастика ли е?).

В заключение - ако имаш дебъг средство за определяне на времето за изпълнение на програмата (аз няма лицензирано такова, а изтече периода на ползване) и ако ти се занимава - можеш да провериш.
Късмет!

Отговор
в отговор на Koтapakът нa Шpьoдинrep #12

Извън кокретната тема- ПИТАМ за DelphiFundamentals

Ползваш ли сокет компонентите? Моля, сподели опит!

Отговор
в отговор на NikB #13

Тц...

ползвам си инди-то засега ми е достатъчно

There are three determined states the cat could be in: Alive, Dead, and Bloody Furious.
Отговор
в отговор на NikB #14

Re: Напълно е възможно :)

ОК, приемам критиката!

По т.1 си прав, говорех наизуст.

По т.2 може да се поспори, но ще задълбаем. Както и да е, само отбелязвам, че скорост на изпълнение и ефективност са две различни понятия по отношение на алгоритмите.

В собствена защита ще изтъкна, че ме събудиха рано, не бях пил кафе още и собствения ми процесор/мозък даваше отклонения от нормата.

> На снимката изглеждаш младо момче ... - не само изглеждам, а и се чувствам така!

> ... та 4004 е първия истински процесор ... - знам, въпреки, че когато той е бил пуснат на пазара, още не съм бил планиран.

> ... а sci-fi научна фантастика ли е? - да.

Мир?

------

[OFF] А твойта снимка де е, че и аз съм любопитен?

Mixy
Отговор
в отговор на Mixy #15

Толкова заядливо ли съм писал :)


Мислех, че съм писал умерено, но явно като не ми върви работата се изнервям.
Въпреки, че в такива случеи поне с кеф се мотая по форумите :)
Късмет!

Отговор
в отговор на PhantomAS #16

Ето ти едно решение, което бачка!

Значи, под 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 битов интеджър с точност до милисекундата, съдържащо време от турско време при това в милисекунди !!!

Майкрософт! Попрекалили сте с уискито ...

Отговор
в отговор на Ц++ #17

А и още нещо ...

Мисля че и Borland-ския TDateTime е базиран на FILETIME. Ако не е, май беше на нещо друго Windows-ко, но каквото и да е в Windows API ще намериш конвертиране от едното в другото. Майкрософт много си обичат техните типове данни и предоставят в API-то си достатъчно много, така че да ги заобичат всички :)

Отговор
в отговор на NDeu #18

10х

Мерси - това ще да е - от грипа нещо не мога да мисля читаво - по точно си мислех за обикновено изваждане ама ми се сториха доста проверките - е не че ги няма ама ме мързеше да мисля.
Между другото намерих нещо ама е платено - ако някой му се дават пари - има доста фунции [линк]

---
Отговор
в отговор на Ц++ #19

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

---
Отговор
в отговор на NikB #20

Re: Не, бе ... :)

Просто не сме се нацелили на кеф.

Карай да е весело. Късмет и на теб!

Mixy
Отговор