DateAndTime printing problem

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

DateAndTime printing problem

NorbertHartl
I discovered a bug in 

DateAndTime>>asParts

which leads to date strings that look like

2010-04-20T14:02:60+00:00

(look at the seconds).  What happens? In DateAndTime>>asParts 

...
x := seconds + offset. "seconds from base"
array at: 7 put: x \\ 60.
...

for a seconds value of 2.9346917950147009E+08 this is

2.9346917950147009E+08 \\ 60 = 5.9501470088958740E+01 

finally in DateAndTime>>printOn: 

...
(x := array at: 7) < 10 ifTrue: [aStream nextPut: $0].
x rounded printOn: aStream.
...

5.9501470088958740E+01 rounded = 60

What would be a short term fix for this? Exchange rounded with asInteger?

Norbert

Reply | Threaded
Open this post in threaded view
|

Re: DateAndTime printing problem

Dale
Norbert,

Here's new implementation of #asPart that gives the right answer:

  2010-04-20T15:13:00+00:00

instead of

  2010-04-20T15:12:60+00:00

I think this fix also takes care or the potential roundoff errors at the minutes, hours and day slots too by basically rounding x up to the nearest 60 seconds:

asParts
        "#(year dayOfYear monthIndex dayOfMonth hour minute second)"

        | x y z array year isLeapYear numDaysArr |
        array := Array new: 7.
        x := seconds + offset. "seconds from base"
        z := x \\ 60.
        z rounded = 60
                ifTrue: [  
                        array at: 7 put: 0.
                        x := x + (60 - (x \\ 60)) ]
                ifFalse: [ array at: 7 put: z ].
        x := x // 60. "minutes from base"
        array at: 6 put: x \\ 60.
        x := x // 60. "hours from base"
        array at: 5 put: x \\ 24.

        x := x // 24. "days from base"
        year := 2001.

        y := x // 146097.
        year := y * 400 + year.
        x := x - (y * 146097). "days since beginning of 400-year cycle"

        y := x // 36524 min: 3.
        year := y * 100 + year.
        x := x - (y * 36524). "days since beginning of 100-year cycle"

        y := x // 1461 min: 96.
        year := y * 4 + year.
        x := x - (y * 1461). "days since beginning of 4-year cycle"

        y := x // 365 min: 3.
        year := y + year.
        x := x - (y * 365) + 1. "days since beginning of year"

        array
                at: 1 put: year;
                at: 2 put: x;
                yourself.
        x <= 31 ifTrue: [
                ^array
                        at: 3 put: 1;
                        at: 4 put: x;
                        yourself.
        ].
        x <= 59 ifTrue: [
                ^array
                        at: 3 put: 2;
                        at: 4 put: x - 31;
                        yourself.
        ].
        isLeapYear := year \\ 4 == 0 _and: [year \\ 100 ~~ 0 _or: [year \\ 400 == 0]].

        isLeapYear ifTrue: [
                x == 60 ifTrue: [
                        ^array
                                at: 3 put: 2;
                                at: 4 put: 29;
                                yourself.
                ].
                x := x - 1.
        ].
        array at: 3 put: 3.
        x := x - 59.

        numDaysArr := #(31 30 31 30 31 31 30 31 30 31)  .
        1 to: numDaysArr size do:[:j | | each |
                each := numDaysArr at: j .
                x <= each ifTrue: [
                        ^array
                                at: 4 put: x;
                                yourself.
                ].
                array at: 3 put: (array at: 3) + 1.
                x := x - each.
        ].
        self error: 'invalid date'.
Reply | Threaded
Open this post in threaded view
|

Re: DateAndTime printing problem

Dale
I've submitted issue 84: http://code.google.com/p/glassdb/issues/detail?id=84 to track this issue...

Dale
----- "Dale Henrichs" <[hidden email]> wrote:

| Norbert,
|
| Here's new implementation of #asPart that gives the right answer:
|
|   2010-04-20T15:13:00+00:00
|
| instead of
|
|   2010-04-20T15:12:60+00:00
|
| I think this fix also takes care or the potential roundoff errors at
| the minutes, hours and day slots too by basically rounding x up to the
| nearest 60 seconds:
|
| asParts
| "#(year dayOfYear monthIndex dayOfMonth hour minute second)"
|
| | x y z array year isLeapYear numDaysArr |
| array := Array new: 7.
| x := seconds + offset. "seconds from base"
| z := x \\ 60.
| z rounded = 60
| ifTrue: [  
| array at: 7 put: 0.
| x := x + (60 - (x \\ 60)) ]
| ifFalse: [ array at: 7 put: z ].
| x := x // 60. "minutes from base"
| array at: 6 put: x \\ 60.
| x := x // 60. "hours from base"
| array at: 5 put: x \\ 24.
|
| x := x // 24. "days from base"
| year := 2001.
|
| y := x // 146097.
| year := y * 400 + year.
| x := x - (y * 146097). "days since beginning of 400-year cycle"
|
| y := x // 36524 min: 3.
| year := y * 100 + year.
| x := x - (y * 36524). "days since beginning of 100-year cycle"
|
| y := x // 1461 min: 96.
| year := y * 4 + year.
| x := x - (y * 1461). "days since beginning of 4-year cycle"
|
| y := x // 365 min: 3.
| year := y + year.
| x := x - (y * 365) + 1. "days since beginning of year"
|
| array
| at: 1 put: year;
| at: 2 put: x;
| yourself.
| x <= 31 ifTrue: [
| ^array
| at: 3 put: 1;
| at: 4 put: x;
| yourself.
| ].
| x <= 59 ifTrue: [
| ^array
| at: 3 put: 2;
| at: 4 put: x - 31;
| yourself.
| ].
| isLeapYear := year \\ 4 == 0 _and: [year \\ 100 ~~ 0 _or: [year \\
| 400 == 0]].
|
| isLeapYear ifTrue: [
| x == 60 ifTrue: [
| ^array
| at: 3 put: 2;
| at: 4 put: 29;
| yourself.
| ].
| x := x - 1.
| ].
| array at: 3 put: 3.
| x := x - 59.
|
| numDaysArr := #(31 30 31 30 31 31 30 31 30 31)  .
| 1 to: numDaysArr size do:[:j | | each |
| each := numDaysArr at: j .
| x <= each ifTrue: [
| ^array
| at: 4 put: x;
| yourself.
| ].
| array at: 3 put: (array at: 3) + 1.
| x := x - each.
| ].
| self error: 'invalid date'.