Between function fails if one argument is time.Now
Closed this issue · 3 comments
I tried getting a period between two dates, one of which is the current time.
year := 2021
month := 3
now := time.Now()
p := period.Between(time.Date(int(year), time.Month(month), 1, 0, 0, 0, 0, now.Location()), now)
However, this panics with the statement:
Periods must have homogeneous signs; got P0Y0M0W190DT19H3M44S
For reference, this was generated at 2021-09-07 19:07:43.2612391 +0900 JST m=+0.109965201 but this was not the only time which generated this panic. What exactly does it mean for a period to not have a homogeneous sign and how can I fix this?
This is not caused by time.Now
.
period.Between
is totally broken if the period is longer than 3276 days (or hours?).
daysDiff
(implementation detail) is meant to deliver a duration in days as components (years, months, days ...). None of the components should be negative. But that doesn't work if you just subtract components of two dates (year, month, day). That's not a duration anymore. It happens after if day > 3276
down below.
func daysDiff(t1, t2 time.Time) (year, month, day, hour, min, sec, hundredth int) {
duration := t2.Sub(t1)
hh1, mm1, ss1 := t1.Clock()
hh2, mm2, ss2 := t2.Clock()
day = int(duration / (24 * time.Hour))
hour = hh2 - hh1
min = mm2 - mm1
sec = ss2 - ss1
hundredth = (t2.Nanosecond() - t1.Nanosecond()) / 100000000
// Normalize negative values
if sec < 0 {
sec += 60
min--
}
if min < 0 {
min += 60
hour--
}
if hour < 0 {
hour += 24
// no need to reduce day - it's calculated differently.
}
// test 16bit storage limit (with 1 fixed decimal place)
if day > 3276 {
y1, m1, d1 := t1.Date()
y2, m2, d2 := t2.Date()
year = y2 - y1
month = int(m2 - m1)
day = d2 - d1
}
return
}
I have not been able to reproduce this issue. The daysDiff function works (only) because it is called with ordered arguments, i.e. t2 is after t1. The fixed-point 16 bit arithmetic is a core part of the design.
The point was and still is, daysDiff
returns something like this: 2023/10/1
-2023/09/21
=0/1/-20
. Positive and negative numbers can occur and later get rejected by period.Between
. First I thought you were using a clever algorithm and correct it later, outside, since it's a private method. The time-Package is able to work with unnormalised time-Values. But that's not the case here.
Correct me where I am wrong. I think I stated the problem correctly back in 2021.
func daysDiff(t1, t2 time.Time) (year, month, day, hour, min, sec, tenth int) {
[...]
if day > 3276 {
y1, m1, d1 := t1.Date()
y2, m2, d2 := t2.Date()
year = y2 - y1
month = int(m2 - m1)
day = d2 - d1
}
^^^ this will produce negative months and days while the year is positive.