It is currently Thu Oct 24, 2019 6:17 am

All times are UTC + 1 hour




Post new topic Reply to topic  [ 15 posts ] 
Author Message
 Post subject: Calculate accurate differences between date/times
PostPosted: Thu Dec 21, 2006 8:13 pm 
Offline
PureBasic Bullfrog
PureBasic Bullfrog
User avatar

Joined: Wed Jul 06, 2005 5:42 am
Posts: 8006
Location: Fort Nelson, BC, Canada
Code updated for 5.20+

I originally posted a version of this yesterday that seemed to work fine, until I noticed some problems. I fixed them, or so I thought, only to discover that more problems existed. It was so unreliable and my attempts at fixing it were so stupid I thought it best to take it down for the time being and see if I could get if working. I damn near despaired, I don't mind admitting. However, a minor brainwave washed over me this morning and I came up with a better approach. After a fair bit of testing I think I have something that can be relied upon to be accurate. If someone can break this, please do and post the results:
Code:
;===================================================
; Program:          DateDiff library function
; Author:           netmaestro
; Date:             December 20, 2006
; Target OS:        Windows All
; Target Compiler:  PureBasic 4.0
; License:          Free, unrestricted, credit
;                   appreciated but not required
;===================================================

Structure TimeDiff
  totaldays.l
  years.l
  months.l
  daysremaining.l
  hours.l
  minutes.l
  seconds.l
EndStructure

Procedure DateDiff(dateearly, datelate, *diff.TimeDiff)
 
  Protected totaldays,years,months,daysremaining,hours,minutes,seconds
 
  curdate = dateearly
  testdate = dateearly
  startday = Day(dateearly)
  totaldays = 0
  daysremaining = 0
 
  While testdate <= datelate
    testdate = AddDate(curdate, #PB_Date_Day, 1)
    If testdate <= datelate
      curdate = testdate
      totaldays+1
      daysremaining+1
      If Day(curdate) = startday
        months+1
        daysremaining=0
      EndIf
    EndIf
  Wend
 
  testdate = curdate
  hours = 0
  While testdate<datelate
    testdate = AddDate(curdate, #PB_Date_Hour, 1)
    If testdate <= datelate
      curdate = testdate
      hours+1
    EndIf
  Wend
 
  testdate = curdate
  minutes = 0
  While testdate<datelate
    testdate = AddDate(curdate, #PB_Date_Minute, 1)
    If testdate <= datelate
      curdate = testdate
      minutes+1
    EndIf
  Wend
 
  testdate = curdate
  seconds = 0
  While testdate<datelate
    testdate = AddDate(curdate, #PB_Date_Second, 1)
    If testdate <= datelate
      curdate = testdate
      seconds+1
    EndIf
  Wend
 
  years = months/12
  If years
    months % 12
  EndIf
 
  *diff\totaldays = totaldays
  *diff\years = years
  *diff\months = months
  *diff\daysremaining = daysremaining
  *diff\hours = hours
  *diff\minutes = minutes
  *diff\seconds = seconds
 
EndProcedure

dateearly = ParseDate("%yyyy/%mm/%dd/%hh:%ii:%ss", "2005/9/9/12:30:00")
datelate = Date()

MyDiff.TimeDiff
DateDiff(dateearly,datelate,@MyDiff)

Debug "Total Days: "+Str(MyDiff\totaldays)
Debug "Years: "+Str(MyDiff\years)
Debug "Months: "+Str(MyDiff\months)
Debug "Days: "+Str(MyDiff\daysremaining)
Debug "Hours: "+Str(MyDiff\hours)
Debug "Minutes: "+Str(MyDiff\minutes)
Debug "Seconds: "+Str(MyDiff\seconds)

_________________
Veni, vidi, vici.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Dec 21, 2006 9:44 pm 
Offline
Addict
Addict

Joined: Mon Apr 28, 2003 2:22 pm
Posts: 942
Location: Europe
I thought about this methode too but there must be a way without doing it in loops or?

_________________
Tranquil


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Dec 22, 2006 1:22 am 
Offline
PureBasic Bullfrog
PureBasic Bullfrog
User avatar

Joined: Wed Jul 06, 2005 5:42 am
Posts: 8006
Location: Fort Nelson, BC, Canada
Well, you can always fall back on the good old windows scripting host. VBScript has a native DateDiff function and you can build a command string, save it to a file and execute it with RunProgram. There's an example of using it to solve an expression here:

http://www.purebasic.fr/english/viewtopic.php?t=24957&start=3

It would just be a matter of modifying it to do DateDiff, shouldn't be hard.

_________________
Veni, vidi, vici.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Dec 22, 2006 8:48 am 
Offline
PureBasic Expert
PureBasic Expert

Joined: Fri Apr 25, 2003 5:24 pm
Posts: 7581
> there must be a way without doing it in loops

DoubleDutch posted a similar tip in 2005 that doesn't use loops:
http://www.purebasic.fr/english/viewtopic.php?t=18366

@netmaestro: Why doesn't your tip show weeks? :)

_________________
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Dec 22, 2006 12:59 pm 
Offline
PureBasic Bullfrog
PureBasic Bullfrog
User avatar

Joined: Wed Jul 06, 2005 5:42 am
Posts: 8006
Location: Fort Nelson, BC, Canada
I'm only looping for one reason, and that's to count accurately the number of calendar months that passed between the two dates. Everything up to weeks can be got easily with arithmetic, as their lengths never change. I'm working on a better version of this using a SYSTEMTIME structure which will handle dates before 1970 and can do stuff like tell you "You've been a human being for 62 years, 3 months, 22 days, 4 hours, 27 minutes and 13 seconds"

_________________
Veni, vidi, vici.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Dec 22, 2006 1:12 pm 
Offline
User
User

Joined: Sun Dec 28, 2003 12:27 am
Posts: 20
Location: Ammerland
What's about this code
Code:
; TimeDiffString : jear Dez 2005

;#TimeUnits = "Woche|n,Tag|e,Stunde|n,Minute|n,Sekunde|n"
#TimeUnits = "week|s,day|s,hour|s,minute|s,second|s"
 
Procedure.s AddTimeUnit(number.l, unit.l)
  Protected Result.s, sUnit.s
  If number = 0 : ProcedureReturn "" : EndIf
  If number < 0 : number * -1 : EndIf
  sUnit = StringField(#TimeUnits, unit, ",")
  If number > 1
    sUnit = RemoveString(sUnit, "|")
  Else
    sUnit = StringField(sUnit, 1, "|")
  EndIf
  Result + Space(1) + Str(number) + Space(1) + sUnit 
  ProcedureReturn Result
EndProcedure

Procedure.s sTimeDiff(Seconds.l)
  Protected Result.s
  Protected Weeks.l, Days.l, Hours.l, Minutes.l
  Weeks   = Seconds / 604800 : Seconds = Seconds % 604800
  Days    = Seconds / 86400  : Seconds = Seconds % 86400
  Hours   = Seconds / 3600   : Seconds = Seconds % 3600
  Minutes = Seconds / 60     : Seconds = Seconds % 60
  Result = AddTimeUnit(Weeks,1)
  Result + AddTimeUnit(Days,2) : Result + AddTimeUnit(Hours,3)
  Result + AddTimeUnit(Minutes,4) : Result + AddTimeUnit(Seconds,5)
  ProcedureReturn Result
EndProcedure

PastDate.l = ParseDate("%dd.%mm.%yyyy", "20.12.2005 12:00")
Debug Date() - PastDate
Debug sTimeDiff(Date() - PastDate)
Delay(2000)
Debug PastDate - Date()
Debug sTimeDiff(PastDate - Date())


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Dec 22, 2006 3:51 pm 
Offline
Addict
Addict

Joined: Wed Aug 24, 2005 8:39 am
Posts: 2736
Location: Southwest OH - USA
netmaestro wrote:
"You've been a human being for 62 years, 3 months, 22 days, 4 hours, 27 minutes and 13 seconds"


Once again, you amaze me. How the heck did you know that?

cheers


Top
 Profile  
Reply with quote  
 Post subject: Re: Calculate accurate differences between date/times
PostPosted: Thu Feb 20, 2014 8:30 pm 
Offline
Addict
Addict

Joined: Wed Aug 24, 2005 8:39 am
Posts: 2736
Location: Southwest OH - USA
If I run the datediff routine above as is, seems OK.

If I change the "test" from
dateearly = ParseDate("%yyyy/%mm/%dd/%hh:%ii:%ss", "2005/9/9/12:30:00")
to
dateearly = ParseDate("%yyyy/%mm/%dd/%hh:%ii:%ss", "2010/12/31/12:30:00") or even
dateearly = ParseDate("%yyyy/%mm/%dd/%hh:%ii:%ss", "2005/10/30/12:30:00")

it appears to fail.

Did anything weird happen on the update to 5.20+ or was it always like this?

cheers


Top
 Profile  
Reply with quote  
 Post subject: Re: Calculate accurate differences between date/times
PostPosted: Thu Feb 20, 2014 8:44 pm 
Offline
Addict
Addict
User avatar

Joined: Mon Jul 25, 2005 3:51 pm
Posts: 3585
Location: Utah, USA
rsts wrote:
If I run the datediff routine above as is, seems OK.

If I change the "test" from
dateearly = ParseDate("%yyyy/%mm/%dd/%hh:%ii:%ss", "2005/9/9/12:30:00")
to
dateearly = ParseDate("%yyyy/%mm/%dd/%hh:%ii:%ss", "2010/12/31/12:30:00") or even
dateearly = ParseDate("%yyyy/%mm/%dd/%hh:%ii:%ss", "2005/10/30/12:30:00")

it appears to fail.


When I tested, it appears to work correctly for the dates you gave. Why are you saying it fails?

_________________
Image


Top
 Profile  
Reply with quote  
 Post subject: Re: Calculate accurate differences between date/times
PostPosted: Thu Feb 20, 2014 8:51 pm 
Offline
Addict
Addict

Joined: Wed Aug 24, 2005 8:39 am
Posts: 2736
Location: Southwest OH - USA
For the original test date I get 8 years 5 months
for the test date of dateearly = ParseDate("%yyyy/%mm/%dd/%hh:%ii:%ss", "2005/10/30/12:30:00")
slightly over 1 month different, I get 7 years 7 months. Or have I gone mad (very possible at this stage :)


Top
 Profile  
Reply with quote  
 Post subject: Re: Calculate accurate differences between date/times
PostPosted: Thu Feb 20, 2014 10:41 pm 
Offline
Addict
Addict
User avatar

Joined: Mon Jul 25, 2005 3:51 pm
Posts: 3585
Location: Utah, USA
rsts wrote:
For the original test date I get 8 years 5 months
for the test date of dateearly = ParseDate("%yyyy/%mm/%dd/%hh:%ii:%ss", "2005/10/30/12:30:00")
slightly over 1 month different, I get 7 years 7 months. Or have I gone mad (very possible at this stage :)


I see the problem now. When I did my tests I looked solely at the day count, which is correct.

The month count is incorrectly calculated. And the year count is based on the possibly faulty month count.


When I have a moment I will post a solution.

_________________
Image


Top
 Profile  
Reply with quote  
 Post subject: Re: Calculate accurate differences between date/times
PostPosted: Thu Feb 20, 2014 11:25 pm 
Offline
Addict
Addict

Joined: Wed Aug 24, 2005 8:39 am
Posts: 2736
Location: Southwest OH - USA
My apologies, Demivec. I should have been clearer as to what the fault was. I was just wondering if the error was introduced in the update to 5.2 or if it had been there all along. I imagine only netmaestro can answer that since I do not have the original source.

Thanks for your assistance in looking at it.

cheers


Top
 Profile  
Reply with quote  
 Post subject: Re: Calculate accurate differences between date/times
PostPosted: Fri Feb 21, 2014 4:44 pm 
Offline
Addict
Addict
User avatar

Joined: Mon Jul 25, 2005 3:51 pm
Posts: 3585
Location: Utah, USA
rsts wrote:
My apologies, Demivec. I should have been clearer as to what the fault was. I was just wondering if the error was introduced in the update to 5.2 or if it had been there all along. I imagine only netmaestro can answer that since I do not have the original source.

Thanks for your assistance in looking at it.

The error wasn't due to anything that changed in v5.21 LTS. The error was in the original code.

As I said earlier, the error is in how the calendar months are counted. Netmaestro compared the starting calendar day to each sequential day in turn, if the day in the month matched the number of months that occurred thus far was incremented.

Unfortunately not all months are the same length. This means if you started on a day (i.e. 1/31 of any year) and counted 40 more days you still wouldn't come to the day '31' of the next month because February would have only 28 or 29 days. This happens at various places around the calendar year and can make the month count inaccurate if the starting day is the 29th, 30th, or 31st of the month.

Because the year count is based off of the month count it will also be affected.

The end result is that the TotalDays count was correct, as were the hours, minutes, seconds. I believe the day count was also correct.


To correct the error you can change line 37 from:
Code:
If Day(curdate) = startday

to
Code:
If Day(curdate) = startday Or (startday > 28 And Day(curdate) = 1 And daysremaining > 3)

_________________
Image


Top
 Profile  
Reply with quote  
 Post subject: Re: Calculate accurate differences between date/times
PostPosted: Fri Feb 21, 2014 6:11 pm 
Offline
Addict
Addict

Joined: Wed Aug 24, 2005 8:39 am
Posts: 2736
Location: Southwest OH - USA
I did not catch that.

Gratitude for your assistance ;)


Top
 Profile  
Reply with quote  
 Post subject: Re: Calculate accurate differences between date/times
PostPosted: Fri Feb 21, 2014 6:37 pm 
Offline
Addict
Addict
User avatar

Joined: Mon Jul 25, 2005 3:51 pm
Posts: 3585
Location: Utah, USA
rsts wrote:
I did not catch that.

Gratitude for your assistance ;)


Your welcome. :)


I forgot to mention what was involved in the change. To properly count a full month of days the line checks for three additional conditions if the simple case fail. The simple case is if the day in the month is the same as the starting day.

Having failed the simple case, the three additional cases are checked for and all need to be met to mark off another month. These conditions are seeing if the starting day is one of the problematic ones (29th, 30th, or 31st), and if the current day is now day 1 (this signals we went from the end of a possibly shorther month to the start of the next month) and finally, if we have counted more than 3 days since the last time the month count was incremented (this last test makes sure the count won't increment unnecessarily for the first few days after a start day of 29, or 30 if this is a long month with 30 or 31 days).

_________________
Image


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 15 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 11 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye