Page 3 of 3 FirstFirst 123
Results 81 to 93 of 93

Thread: Calculating exact time in Years, MOnths, Days

  1. #81
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    26,413

    Re: Calculating exact time in Years, MOnths, Days

    Quote Originally Posted by dbasnett View Post
    When you look it over you might find weeks.

    BTW - IMHO this is an error

    0 years, 0 months, 30 days between 1/29/2005 2/28/2005
    0 years, 1 months, 1 days between 1/29/2005 3/1/2005
    1/29/2005 is a non existent date

  2. #82
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Calculating exact time in Years, MOnths, Days

    I think some good points are in #63, #67 (personal comments aside), and #73. I think .paul. missed the two points in #69. As of #60 I decided to explicitly state a lack of confidence that I'd hit all edge cases and I'm no longer claiming correctness. I tested many edge cases but knew there were likely several I missed.

    My "essays" (ask dbasnett about me, he's seen my *real* essays) are to highlight the points I felt were pertinent. I like word-heavy posts because I think it's nearly criminal to aid and abet copypasta programmers. In this case it doesn't matter; odds are any example won't have the domain-specific logic the programmer wants. Here's what I think is important now:
    1. This is a tough algorithm to get right; simple code is probably a better idea than complicated code.
    2. Days are the only unit easily and accurately counted. All others require difficult logic.
    3. There is no consensus on the "right" answer to certain time spans except when expressed in days. The domain specifies expected behavior.
    4. DateDiff() is often harder to use than rewrite yourself.
    5. I'm not sure if all edge cases have been enumerated; I think that's the best first step.
    6. Based on #5, the best we can do is test *many* edge cases and use that as our confidence all cases are covered.

    I'm not interested in a third attempt because of #5. Call me chicken, but at this point I think it'd be a bit hypocritical to post another code sample if I'm not absolutely certain it works. Also, I'm not certain anyone's posted a critique of #60 so I'm going to assume it works until I've run dbasnett's test cases from #74. Plus, I want to see dbasnett's approach; I haven't opened VS 2010 yet today. I wouldn't want to waste time writing something he's already written.

    I think the only "good" way to verify this would be a brute-force approach. It's a simple matter to keep adding days to an end date and period, then comparing the results to the expected value. The trick is figuring out how long a time span is adequate for correctness. I think I have an idea and I'm going to work on that test harness instead of any further attempts at a "correct" algorithm.

    The concept of counting weeks makes me shiver, but I don't think it's as complicated on its own as it is incorporated to the other counter. Pseudocode:
    Code:
    Let weeks = 0
    Let currentDate = startDate
    While currentDate < endDate
        Add 7 days to currentDate
        If currentDate < endDate Then
            Add 1 to weeks
        End If
    End While
    Of course this has the same problems with domain-specific requirements as the rest. You might be picky about whether this is off by 1, or you might only want to count full weeks, or you might only want full business weeks. Each of those has its own complexities.

    This is why I think DateDiff() fails. It tries to address *all* of these scenarios rather than addressing very specific scenarios. I don't think it's wise to write a general-purpose *function* to calculate these ranges. A class with several specific functions seems better.

  3. #83
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: Calculating exact time in Years, MOnths, Days

    Quote Originally Posted by Sitten Spynne View Post
    ...My "essays" (ask dbasnett about me, he's seen my *real* essays) are to highlight the points I felt were pertinent.
    1. This is a tough algorithm to get right; simple code is probably a better idea than complicated code.
    2. Days are the only unit easily and accurately counted. All others require difficult logic.
    3. There is no consensus on the "right" answer to certain time spans except when expressed in days. The domain specifies expected behavior.
    4. DateDiff() is often harder to use than rewrite yourself.
    5. I'm not sure if all edge cases have been enumerated; I think that's the best first step.
    6. Based on #5, the best we can do is test *many* edge cases and use that as our confidence all cases are covered.


    .... Also, I'm not certain anyone's posted a critique of #60 so I'm going to assume it works until I've run dbasnett's test cases from #74. Plus, I want to see dbasnett's approach; I haven't opened VS 2010 yet today. I wouldn't want to waste time writing something he's already written.

    I think the only "good" way to verify this would be a brute-force approach. It's a simple matter to keep adding days to an end date and period, then comparing the results to the expected value. The trick is figuring out how long a time span is adequate for correctness. I think I have an idea and I'm going to work on that test harness instead of any further attempts at a "correct" algorithm.
    "I'm not sure if all edge cases have been enumerated; I think that's the best first step." I have an idea of what I mean and I will post my definition.

    I agree about the brute force method. My attempt at that is in post #58.

    I am still cleaning up the code and will post it in post #2 as I work on it. After 5 or 6 days of fooling with this I am in no hurry.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  4. #84
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Calculating exact time in Years, MOnths, Days

    Quote Originally Posted by .paul. View Post
    1/29/2005 is a non existent date
    You might want to rethink that.

    In other news, brute force fell flat. In order for my technique to work, you have to have a way to calculate the "expected" range. Calculating the expected range is what the algorithm is trying to do; you can't test something with itself. I'm not sure I trust #58 either; all you're doing is testing one algorithm for calculating the range against another. Rats.

    Haven't spent much time on the revised #2; I can't figure out which pieces are important and which pieces aren't. I'll wait until you've got something presentable while I ruminate on the test cases.
    Last edited by Sitten Spynne; Jul 27th, 2011 at 10:31 AM.

  5. #85
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    26,413

    Re: Calculating exact time in Years, MOnths, Days

    Quote Originally Posted by Sitten Spynne View Post
    You might want to rethink that.

    In other news, brute force fell flat. In order for my technique to work, you have to have a way to calculate the "expected" range. Calculating the expected range is what the algorithm is trying to do; you can't test something with itself. I'm not sure I trust #58 either; all you're doing is testing one algorithm for calculating the range against another. Rats.

    Haven't spent much time on the revised #2; I can't figure out which pieces are important and which pieces aren't. I'll wait until you've got something presentable while I ruminate on the test cases.
    yep.. i was thinking 2/29/2005

  6. #86
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: Calculating exact time in Years, MOnths, Days

    Quote Originally Posted by Sitten Spynne View Post
    You might want to rethink that.

    In other news, brute force fell flat. In order for my technique to work, you have to have a way to calculate the "expected" range. Calculating the expected range is what the algorithm is trying to do; you can't test something with itself. I'm not sure I trust #58 either; all you're doing is testing one algorithm for calculating the range against another. Rats.

    Haven't spent much time on the revised #2; I can't figure out which pieces are important and which pieces aren't. I'll wait until you've got something presentable while I ruminate on the test cases.
    1/29/2005 does (did) exist.

    Read #42 to see why I think #58 works.

    Here is a simple example of how to use the code in #2

    Code:
        Private Sub Button4_Click(sender As System.Object, e As System.EventArgs) Handles Button4.Click
            Try
                Dim foo As New AgeCalc(Date.Parse(TextBox1.Text), Date.Parse(TextBox2.Text))
                Dim bar As Age = foo.AgeInYearsMonthsDays
                Label1.Text = bar.Years.ToString & "  " & bar.Months.ToString & "  " & bar.Days.ToString
            Catch ex As Exception
    
            End Try
        End Sub
    Try these date pairs for controversy:

    1/30/2005 - 4/30/2005

    1/31/2005 - 4/30/2005
    Last edited by dbasnett; Jul 27th, 2011 at 11:38 AM.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  7. #87
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Calculating exact time in Years, MOnths, Days

    I'm still not convinced. The algorithm you describe in #42 is very similar to my #8. If so, and #8 has flaws, how can you trust checking against a flawed algorithm?

    In other news, I just sat down and banged out what I think is a fairly exhaustive list of test cases. I listed 98 (I think!) but could have thought of nearly 150 if I felt really paranoid. To test day calculations, I picked all for month lengths and picked easy dates within the month. To test month calculations, I noted there were several combinations of month lengths. First, I crossed each month boundary (31, 30, 29, and 28 days) and verified the (1m, 0d) date and the two boundary dates. (The * before some tests indicates previous tests have technically covered that case.) For fun, I tested from July-September, one of the two 31-31 boundaries. I did a cursory test of the Dec-Jan boundary to catch erroneous year increments. Then I listed 31-30, 31-29, and 31-28. At this point I felt month calculations were adequately tested, but other possible tests include the boundaries 30-31, 31-31-30, 31-30-31, and 30-31-30 (they would have been more interesting in an algorithm attempting to go from days -> months directly.) Year calculations don't have to be as thorough: I tested Jan-Jan and Jan-Mar (leap and non-leap.) Finally, calculations across leap years are tested in all scenarios I could think of: first year is leap, 1 leap year is spanned, no leap year in range, end year is leap, and multiple leap years spanned.

    So far I can't think of any relevant situations not listed.

    It's possible I'm off by one on the "expected" dates. I triple-counted using a calendar, but the font was small and I tend to get cross-eyed trying to count dates like that. I'm too lazy to type up a harness that uses them all; I've spent enough time on forums today anyway Maybe I'll unleash it against my stuff later tonight.
    Attached Files Attached Files

  8. #88
    Hyperactive Member
    Join Date
    Apr 2011
    Location
    England
    Posts
    421

    Re: Calculating exact time in Years, MOnths, Days

    For no other reason than, "I started so I'll finish" here is the latest revision of my own method which I am confident will pass any stress tests

    I made a better test function to help me conclude this. It specifies a startdate. It then tests this against every possible end date upto 366 days from the start date. It will then increase the startdate by 1 day and cycle this again. It ends when the startdate reaches 366 days from the given date. OK I think i've confused us all enough now!

    dbasnett, you will be glad to know I tested it on your code too, and there are no errors in yours either

    Here's the code:
    VB.NET Code:
    1. Public Class Form1
    2.  
    3.     'Date1 is the lowest date, Date2 is the highest date
    4.     Private Sub DateCompare(ByVal Date1 As Date, ByVal Date2 As Date)
    5.  
    6.         Dim Days As Integer = Nothing
    7.         Dim Months As Integer = Nothing
    8.         Dim Years As Integer = Nothing
    9.  
    10.         'Convert Date1/Date2 months and years into months.
    11.         Dim Date1Months As Integer = Date1.Year * 12 + Date1.Month
    12.         Dim Date2Months As Integer = Date2.Year * 12 + Date2.Month
    13.         'Get the number of Months between the two dates. Subtract 1 (we will add this back later where necessary)
    14.         Months = Date2Months - Date1Months - 1
    15.  
    16.         'See how many days are within the Month Date1/Date2 reside.
    17.         Dim DaysInDate1Month As Integer = Date.DaysInMonth(Date1.Year, Date1.Month)
    18.         Dim DaysInDate2Month As Integer = Date.DaysInMonth(Date2.Year, Date2.Month)
    19.  
    20.  
    21.         If Date1.Day = DaysInDate1Month And Date2.Day = DaysInDate2Month Then
    22.             'If Both Date1 and Date2 occur on the LastDayOfTheMonth.
    23.  
    24.             'We count this as a month rather than x amount of days.
    25.             'Therefore add 1 to Months and set Days to zero.
    26.             'nb: We subtracted a month when we first grabbed the number of Months. Add it back here.
    27.             Months += 1
    28.             Days = 0
    29.         ElseIf Date1.Day = DaysInDate1Month And Date2.Day < DaysInDate2Month Then
    30.             'If Date1 occur's on the LastDayOfTheMonth but Date2 resides on a day prior to the end of it's month.
    31.  
    32.             'We know the number of Days between the two dates will be the number of Days in Date2.
    33.             Days = Date2.Day
    34.         ElseIf Date1.Day > DaysInDate2Month And Date2.Day = DaysInDate2Month Then
    35.             Months += 1
    36.             Days = 0
    37.         Else
    38.             'If Neither Date1 or Date2 occur on the LastDayOfTheMonth then we can do a day count ourselves.
    39.             Select Case Date1.Day
    40.  
    41.                 Case Is < Date2.Day
    42.                     'If Date2's Day is higher then Date1's Day then the 'Months' value will represent the number of months upto the Month that Date2 resides.
    43.  
    44.                     'The number of days will therefore be the difference between Date1/Date2's Day values.
    45.                     Days = Date2.Day - Date1.Day
    46.  
    47.                     'nb: We subtracted a month when we first grabbed the number of Months. Add it back here.
    48.                     Months += 1
    49.                 Case Is > Date2.Day
    50.                     'If Date2's Day is lower then Date1's Day then the 'Months' value will represent the number of months upto the Month prior to that which Date2 resides.
    51.  
    52.                     'First we need to find out the month prior to Date2's month value.
    53.                     Dim MonthBeforeDate2 As Integer = Date2.Month
    54.                     'If Date2 occurs in January, then we will also need to use the previous year in our calculation.
    55.                     Dim Date2Year As Integer = Date2.Year
    56.                     If MonthBeforeDate2 = 1 Then
    57.                         MonthBeforeDate2 = 12
    58.                         Date2Year -= 1
    59.                     Else : MonthBeforeDate2 -= 1
    60.                     End If
    61.  
    62.                     'If there are more days in Date1 than occur in the month prior to Date2 then we want to avoid calculating the days that remain in that month.
    63.                     'As that would lead to a neagtive value.
    64.                     If Date1.Day > Date.DaysInMonth(Date2Year, MonthBeforeDate2) Then
    65.                         'In this case we only need the number of days in Date2.
    66.                         Days = Date2.Day
    67.                     Else
    68.                         'Next we will see how many days occur between the value of Date1's Day and the end of the month prior to Date2.
    69.                         Dim DaysLeftInMonthBeforeDate2 As Long = Date.DaysInMonth(Date2Year, MonthBeforeDate2) - Date1.Day
    70.  
    71.                         'Finally we can add the number of Days in Date2.
    72.                         Days = DaysLeftInMonthBeforeDate2 + Date2.Day
    73.                     End If
    74.  
    75.                 Case Is = Date2.Day
    76.                     'If the Day value in Date1/Date2 matches.
    77.  
    78.                     'nb: We subtracted a month when we first grabbed the number of Months. Add it back here.
    79.                     Months += 1
    80.             End Select
    81.  
    82.         End If
    83.  
    84.         'The last step is to work out the number of Years. We can work this out from the 'Months'.
    85.         'nb: We left this until last because there may have been a few neccessary changes to the Months value along the way.
    86.         If Months >= 12 Then
    87.             Do Until Months < 12
    88.                 Years += 1
    89.                 Months -= 12
    90.             Loop
    91.         End If
    92.  
    93.         'Now just format the result:
    94.         MsgBox(String.Format("Years: {1}{0}Months: {2}{0}Days: {3}{0}", {vbCrLf, Years, Months, Days}))
    95.  
    96.     End Sub
    97.  
    98. End Class

  9. #89
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: Calculating exact time in Years, MOnths, Days

    @jay - Depending on how you define a leaplings birthday this may or may not be an error

    1 years, 0 months, 0 days between 2/29/2004 2/28/2005

    This is how I define it

    0 years, 11 months, 30 days between 2/29/2004 2/28/2005
    1 years, 0 months, 0 days between 2/29/2004 3/1/2005
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  10. #90
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: Calculating exact time in Years, MOnths, Days

    @sitten et al, I am trying to nail down my definition.

    http://www.vbforums.com/showpost.php...40&postcount=2
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  11. #91
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Calculating exact time in Years, MOnths, Days

    Quote Originally Posted by dbasnett View Post
    @jay - Depending on how you define a leaplings birthday this may or may not be an error

    1 years, 0 months, 0 days between 2/29/2004 2/28/2005

    This is how I define it

    0 years, 11 months, 30 days between 2/29/2004 2/28/2005
    1 years, 0 months, 0 days between 2/29/2004 3/1/2005
    That's the kind of thing I'm complaining about though; to some people you're wrong and Feb 29 N to Mar 1 N + 1 is a year. If that's the only miscalculation in an algorithm I say the calculation's correct; it's easy enough to correct the "flaw" with an If statement.

  12. #92
    Hyperactive Member
    Join Date
    Apr 2011
    Location
    England
    Posts
    421

    Re: Calculating exact time in Years, MOnths, Days

    Quote Originally Posted by dbasnett View Post
    @jay - Depending on how you define a leaplings birthday this may or may not be an error

    1 years, 0 months, 0 days between 2/29/2004 2/28/2005

    This is how I define it

    0 years, 11 months, 30 days between 2/29/2004 2/28/2005
    1 years, 0 months, 0 days between 2/29/2004 3/1/2005
    'Leaplings' can celebrate a birthday on either 28/02 or 01/03 in any standard year. It is common to opt for the latter because it is the day following Feb 28th as was the case of the day of their birth.
    I did weigh up the leapling idea, but decided to leave it as is. My reasoning is that if you count the days between these dates:


    28/2/2003 - 29/2/2004 = 366 days
    29/2/2004 - 28/2/2005 = 365 days
    28/2/2005 - 28/2/2006 = 365 days
    28/2/2006 - 28/2/2007 = 365 days
    28/2/2007 - 29/2/2008 = 366 days


    by definition a leap year occurs every 4 years. I take that to mean a year is equal to 365 days for 3 consecutive years, followed by a non-standard year of 366 days.
    If we were to take the leapling route then the dates above would be written:


    28/2/2003 - 29/2/2004 = 366 days
    29/2/2004 - 01/3/2005 = 366 days


    Upto now we have 2 consective years that calculate as 366 days. Now since 01/03 has been used to define the end of year that begins on a leapling, do we now consider the start of the next year from the 01/03? If so we would be looking at losing a day in order to re-align the years:


    01/3/2005 - 28/2/2006 = 364 days
    28/2/2006 - 28/2/2007 = 365 days
    28/2/2007 - 29/2/2008 = 366 days


    and therefore the consistency of the year by definition has been thrown out of the window. Perhaps my view is wrong though, but as Sitten Spynne has maintained throughout, details such as these really come down to invidual interpretation because there is no set standard to govern this.



    A couple of results from your function:

    28/2/2003 - 29/2/2004 = 1 year, 1 day (366 days)
    29/2/2004 - 28/2/2005 = 11 Months, 30 Days (11 months = 01/03 to 31/01, that is 336 days. Then add the 30.)
    Last edited by JayJayson; Jul 28th, 2011 at 12:22 AM.

  13. #93
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: Calculating exact time in Years, MOnths, Days

    @jay - However you decide to treat a leapling's birthday is fine with me. I think we all have come to the conclusion that time expressed in anything other than days(TimeSpan accuracy) is arbitrary.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

Page 3 of 3 FirstFirst 123

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width