-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
year 0 in time.Time is valid but always throws an error #1223
Comments
A quick guess, is your issue related to this? |
hi @proyb6, thanks for the hint. (unrelated to my issue, and related to the one you linked: since |
hi @zihengCat, yes, that is exactly it! year 0 is in fact "out of range" for a |
Well, let the maintainers @julienschmidt @methane @shogo82148 join the discussion. Seems that it's a breaking change between v1.5.0 and v.1.6.0, but isn't described clearly in release notes. Should the MySQL |
i updated the description with a minimal reproducible example. |
We shouldn't treat MySQL In the following case, the driver converts db.Exec("update `time_test` set some_time = ? where id = 1;", parsedTime) However, it is not valid value for MySQL
And, MySQL
https://play.golang.org/p/tiJAvWu4vt2 package main
import (
"fmt"
"time"
)
func main() {
mysqlTimeFormat := "15:04:05"
fmt.Println(time.Parse(mysqlTimeFormat, "-838:59:59"))
// Output:
// 0001-01-01 00:00:00 0000 UTC parsing time "-838:59:59" as "15:04:05": cannot parse "-838:59:59" as "15"
} |
Time conversion codes used in Lines 244 to 254 in 75d09ac
It's hard to pre-detect MySQL If top layer passes a |
Leave things to the top layer is much simpler, just using func main() {
someTime := time.Date(0, 0, 0, 8, 30, 30, 0, time.UTC)
parsedTime := timeParse(someTime) // "08:30:30"
if _, err := db.Exec("update `time_test` set some_time = ? where id = 1;", parsedTime); err != nil {
panic(err)
}
}
func timeParse(t time.Time) string {
var buf bytes.Buffer
h, m, s := t.Clock()
if h < 10 {
buf.WriteString("0")
}
buf.WriteString(strconv.Itoa(h))
buf.WriteString(":")
if m < 10 {
buf.WriteString("0")
}
buf.WriteString(strconv.Itoa(m))
buf.WriteString(":")
if s < 10 {
buf.WriteString("0")
}
buf.WriteString(strconv.Itoa(s))
return buf.String()
} |
@shogo82148 thank you for looking at it the issue. i'm of course fine with you saying that throwing that error is an intended fix. it's a breaking change though so in that case it should be noted somewhere. i must admit i didn't check the mysql warnings, it's indeed not fully correct in 1.5.0 and it just happened to be working.
sorry for the confusion. my issue is only about the writing of the about parsing (which, again, the issue isn't about): you are right that it would not be correct to generally use
your code can be much simpler too: someTime := time.Date(0, 0, 0, 8, 30, 30, 0, time.UTC)
mysqlTimeFormat := "15:04:05"
fmt.Println(someTime.Format(mysqlTimeFormat)) my issue isn't with getting it to work, it's that writing such a value "worked" in 1.5.0, but doesn't in 1.6.0, and i was wondering if it's fully intentional 🙂 edit: if you are not completely against it, i can open a pr with my suggestion, and we could discuss some actual code. |
MySQL Now, the question is, what Go data type should we use to map MySQL
However |
@zihengCat This issue is not about how to "represent" a MySQL (Again, this is unrelated to the issue, but |
I don't think Is there any other formal document about "time of the day" ("time without date") in time Pacakge? |
@methane just to make sure we are on the same page, i'm talking about this paragraph:
this is quoted from the description of another point is the following quote, from the paragraph above the one already quoted:
and the value of the constant as far as i can tell, there is no other way of representing just a time without a date mentioned in the package description. about your other question:
i think i kept saying the wrong thing because i abbreviated it too much. of course you are right: based on the description i quoted, it's not just about the year being 0, but the other date values being not set as well. so any note that your code currently does not accept your second example, and the full range of valid years: "Years must be in the range 0000..9999". year 0 should be allowed no matter how you stand on the "time without a date" issue, and it is currently not. |
Any Additionally, "1000-01-01 00:00:00" can be just an Year (note that MySQL has "YEAR" type), full datetime, or any partial values.
I had not say we should support second example. So not supporting second example is not a problem here.
I can not understand this sentences. If I stand on the "time without date is just a hack and we should not support it" side, why should I support 0 year? |
hi @methane, thanks for the quick reply :D
you are right. unfortunately (for me, right now 😬) the golang developers chose an implicit representation instead of an explicit one (probably for a good reason). and you already support these in your code:
Here is the quote again from the description of time.Parse():
i read this as: year 0 is a completely valid value. PS: i implemented the suggested changes in #1240. |
about the year 0: actually you are right, it should not be supported. it is not a valid year for mysql. but so is any year < 1000.
so the proper check should be for Line 285 in e8f8fcd
this also makes a |
I think this issue is "do or do not", not "which is right" problem. I want to add support of "time without date" if we can scan it into |
At least, I don't accept #1240 at this time. For a workaround, Go provides some interfaces that allow to use your custom types as You can implement the MySQL's TIME type using them. // MySQLTime is the MySQL's TIME type.
type MySQLTime struct { /* TOOD: implement it */ }
func (t *MySQLTime) Scan(src interface{}) error {
return errors.New("not implemented") // TODO: fix me
}
func (t MySQLTime) Value() (driver.Value, error) {
return "08:30:30", nil
} |
hello, sorry for the late response, i was on vacation 🙂
you're absolutely right about that! it seems to me that the change in behaviour is a symptom of the fact that it's not clear yet what the right thing to do is.
it is definitely possible, however as others in this thread noted it's not entirely straightfoward because a MySQL
a "time of day" format can be parsed into a
@shogo82148 |
@methane @shogo82148 is there anything i can do to move this forward? |
hi, have you had some time to think about this issue? to reiterate, i'm mostly interested in an official statement about how to deal with the behaviour change from v1.5.0 to v.1.6.0. |
hi @methane @shogo82148, did you maybe reach a verdict? can i help with anything? so far my "workaround" was to not update this dependency in my code, but now e.g. the pretty popular |
I see that this is somewhat old and I found it while I was on the quest for the Just an example: t1, _ := time.Parse("03:04:05", "00:00:00")
t2 := time.Now().Add(t1.Sub(time.Time{})).Format("2006-01-02 03:04:05") This will create a time value at midnight of "no give year/month/date" and then adds the duration out of the "zero" year and this time to "now". The result will be one year in the past, and that does not make much sense to me. The way I do not see a reason why they made it like this. If year 0 is invalid, then it should panic when using that in a calculation. I now use |
Issue description
after upgrade from v1.5.0 to v.1.6.0, a
time.Time
representing an actual time without a date cannot be inserted into a column of typeTIME
any longer, as it has year 0 set. funnily, this value was previously even retrieved from the DB. year 0 is also in general not an invalidtime.Time
value for real dates.from https://golang.org/pkg/time/#Parse :
the following recently added line throws an error when the year is 0:
mysql/utils.go
Line 285 in 417641a
as far as i can see,
appendDateTime()
, the function which contains this line, is called twice, and both times when the giventime.Time
does not have its zero value as determined byIsZero()
. however, the zero value for atime.Time
is in year 1, see https://golang.org/pkg/time/#Time.IsZero :what is the reason the range was picked to be
[1, 9999]
here?if you can confirm this is actually an issue, i'm willing to try and fix it 🙂
Example code
Error log
the error i receive is the error from the line i specified above:
panic: year is not in the range [1, 9999]: 0
Configuration
Driver version (or git SHA): v1.6.0
Go version: 1.16.2
Server version: MySQL 8.0.20
Server OS: official mysql docker container, iirc its based on debian but should be irrelevant.
The text was updated successfully, but these errors were encountered: