I am trying to do find the time difference between time now from the created at column in the database
I return a row in the database, i have the created_at column with the following time format
{"id":1,"email":"fUPvyBA#FApYije.ru","timezone":"pacific time","created_at":"2022-01-23T02:45:01.241589Z","updated_at":"2022-01-23T02:46:01.241591Z"}
so created_at = 2022-01-23T02:45:01.241589Z
and
time.Now() = 2022-01-24 03:24:56.215573343 +0000 UTC m=+1325.103447033
I tested with the following
import (
"fmt"
"time"
)
func TestTime() {
timestart := "2022-01-23T02:45:01.241589Z"
timeend := time.Now()
timediff := timeend.Sub(timestart)
fmt.Println("time diff is: ", timediff.Seconds())
}
TestTime()
but i get the following errors
cannot use <string> as <time.Time> in argument to timeend.Sub
How do i subtract to get the difference between the time i stored in created_at column from the current time time.Now()?
The error means that you trying to use an string on a time.Time parameter
Try this:
import (
"fmt"
"time"
)
func TestTime() {
layout := time.RFC3339 // "2006-01-02T15:04:05Z07:00"
timestart, err := time.Parse(layout, "2022-01-23T02:45:01.241589Z")
if err != nil {
panic(err)
}
timeend := time.Now()
timediff := timeend.Sub(timestart)
fmt.Println("time diff is:", ltimediff.Seconds())
}
TestTime()
Related
I am wanting to make sure that the DOB(Date of Birth) is formatted professionally and clearly instead of being a bland integer. I have tried using a constant to declare the layout like this
const (
layoutISO = "2006-01-02"
layoutUS = "January 2, 2006"
)
date := "1999-12-31"
t, _ := time.Parse(layoutISO, date)
fmt.Println(t) // 1999-12-31 00:00:00 +0000 UTC
fmt.Println(t.Format(layoutUS)) // December 31, 1999
but I can't seem to fit this into my context
package main
import (
"fmt"
)
func main() {
const (
layoutISO = "2006-01-02"
layoutUS = "January 2, 2006"
)
type aUser struct {
userID int
username string
email string
DOB int64
registeredAt int64
}
type note struct {
name string
status string
users []aUser
}
sally := aUser{01, "Sally", "sally#gmail.com", 112498, 1935}
john := aUser{02, "John", "johnme#gmail.com", 112388, 1978}
users := []aUser{sally, john}
notes := note{"Grocery List", "Completed", users}
fmt.Printf("notes are %v\n", notes)
}
You can extract year/month/date from the numeric type with division and modulo operations, then write them to a string using C-style string formatting with fmt.Sprintf().
var dob uint64 = 112498
date := fmt.Sprintf("19%02d-%02d-%02d", dob % 100, dob / 10000, (dob / 100) % 100)
fmt.Println(date) // 1998-11-24
Be warned your date format is missing century and millennium information, so in the above code I guessed that the year is 19XX (as opposed to 20XX, etc.).
I have current time and past time, Im trying to findout difference in minutes.
Here is my code im trying, although im new to go.
package main
import (
"fmt"
"time"
)
func main() {
//fetching current time
currentTime := time.Now().Format("2006-01-02 15:04:05")
//past time comes in as string
pasttimestr := "2018-10-10 23:00"
layout := "2006-01-02 15:04:05"
//converting string to date
pasttime, err := time.Parse(layout, pasttimestr)
if err != nil {
fmt.Println(err)
}
//differnce between pastdate and current date
diff := currentTime.Sub(pasttime)
fmt.Println("difference time in min : ", diff)
}
Error:
# command-line-arguments
.\dates.go:21:21: currentTime.Sub undefined (type string has no field or method Sub)
Thanks in advance :)
You should probably remove the format function call from current time to get the actual time struct rather than a string representation and and fix the layout for past time
package main
import (
"fmt"
"time"
)
func main() {
//fetching current time
currentTime := time.Now()
loc := currentTime.Location()
//past time comes in as string
pasttimestr := "2018-10-10 23:00"
layout := "2006-01-02 15:04"
//converting string to date
pasttime, err := time.ParseInLocation(layout, pasttimestr, loc)
if err != nil {
fmt.Println(err)
}
fmt.Println("Past Time: ", pasttime)
fmt.Println("Current Time: ", currentTime)
//differnce between pastdate and current date
diff := currentTime.Sub(pasttime)
fmt.Printf("time difference is %v or %v in minutes\n", diff, diff.Minutes())
}
Gives me
Past Time: 2018-10-10 23:00:00 -0400 EDT
Current Time: 2018-10-10 14:31:34.865259 -0400 EDT m=+0.000351797
time difference is -8h28m25.134741s or -508.41891235 in minutes
Drop the .Format() function call on time.Now() like below. Also I've updated the layout string to match the format for pasttimestr.
func main() {
//fetching current time
currentTime := time.Now()
//past time comes in as string
pasttimestr := "2018-10-10 23:00"
layout := "2006-01-02 15:04"
//converting string to date
pasttime, err := time.Parse(layout, pasttimestr)
if err != nil {
fmt.Println(err)
}
//differnce between pastdate and current date
diff := currentTime.Sub(pasttime)
fmt.Println("difference time is : ", diff)
}
Output
difference time is : -4h36m32.001213s
I have a table with timestamp TIMESTAMP, data TEXT columns. I have a failing test because I can't get a timestamp value out of postgresql without time zone annotation. Here's an abridged version of what I've done in my Go application:
type Datapoint struct {
Timestamp string
Data sql.NullString
}
var testData = Datapoint{Timestamp:'2018-12-31 00:00:00', Data:'test'}
db.Exec("CREATE TABLE mytable (id SERIAL, timestamp TIMESTAMP, data TEXT);")
db.Exec("INSERT INTO mytable(timestamp, data) VALUES ($1, $2);", testData.Timestamp, testData.Data)
datapoints, err = db.Exec("SELECT timestamp::TIMESTAMP WITHOUT TIME ZONE, data FROM mytable;")
This trouble is that this query (after about 20 lines of error checking and row.Scan; golang's a bit verbose like that...) gives me:
expected 2018-12-31 00:00:00, received 2018-12-31T00:00:00Z
I requested without timezone (and the query succeeds in psql), so why am I getting the extra T and Z in the string?
Scan into a value of time.Time instead of string, then you can format the time as desired.
package main
import (
"database/sql"
"fmt"
"log"
"time"
)
type Datapoint struct {
Timestamp time.Time
Data sql.NullString
}
func main() {
var db *sql.DB
var dp Datapoint
err := db.QueryRow("SELECT timestamp, data FROM mytable").Scan(
&dp.Timestamp, &dp.Data,
)
switch {
case err == sql.ErrNoRows:
log.Fatal("No rows")
case err != nil:
log.Fatal(err)
default:
fmt.Println(dp.Timestamp.Format("2006-01-02 15:04:05"))
}
}
What you are receiving is an ISO 8601 representation of time.
T is the time designator that precedes the time components of the representation.
Z is used to represent that it is in UTC time, with Z representing zero offset.
In a way you are getting something without a timezone but it can be confusing, especially as you haven't localised your time at any point. I would suggest you consider using ISO times, or you could convert your time to a string like this
s := fmt.Sprintf("%d-%02d-%02d %02d:%02d:%02d\n",
t.Year(), t.Month(), t.Day(),
t.Hour(), t.Minute(), t.Second())
Any ideas how to get golang to properly parse a date string such as 31916
I keep getting a month out of range error.
date, err := time.Parse("1206", "31916")
fmt.Println(date, err)
Of course I want to treat the month as 3 and not 31 like it's doing, but I'm not sure how to force it to stop at 3 for the month outside of adding separators to the format.
For example,
package main
import (
"fmt"
"time"
)
func parseDate(date string) (time.Time, error) {
if len(date) == 5 {
date = "0" + date
}
return time.Parse("010206", date)
}
func main() {
date, err := parseDate("31916")
fmt.Println(date, err)
date, err = parseDate("031916")
fmt.Println(date, err)
date, err = parseDate("121916")
fmt.Println(date, err)
}
Output:
2016-03-19 00:00:00 +0000 UTC <nil>
2016-03-19 00:00:00 +0000 UTC <nil>
2016-12-19 00:00:00 +0000 UTC <nil>
You can't. The layout you pass is not deterministic - there is no way for Go to know when the month ends and the day starts in your string - besides when one option fails and the other one does not (think of "11106" - is that 1\11\06 or 11\1\06?). Your best bet is to write a wrapper which makes the choice deterministic:
import (
"time"
"strconv"
)
func parseWeirdLayout(dateString string) (time.Time, error) {
parsedString := ""
if len(dateString) == 5 {
month, err := strconv.Atoi(dateString[0:2])
if err != nil {
return time.Now(), err
}
if month < 1 || month > 12 {
parsedString = "0" + dateString
} else {
parsedString = dateString[:2] + "0" + dateString[2:]
}
} else if len(dateString) == 4 {
parsedString = "0" + dateString[:1] + "0" + dateString[1:]
}
return time.Parse("010206", parsedString)
}
Test here: https://play.golang.org/p/u1QFPzehMj
Or simply use a different, deterministic layout, e.g. "010206".
Situation:
I'm using a postgres database and have the following struct:
type Building struct {
ID int `json:"id,omitempty"`
Name string `gorm:"size:255" json:"name,omitempty"`
Lon string `gorm:"size:64" json:"lon,omitempty"`
Lat string `gorm:"size:64" json:"lat,omitempty"`
StartTime time.Time `gorm:"type:time" json:"start_time,omitempty"`
EndTime time.Time `gorm:"type:time" json:"end_time,omitempty"`
}
Problem:
However, when I try to insert this struct into the database, the following error occurs:
parsing time ""10:00:00"" as ""2006-01-02T15:04:05Z07:00"": cannot
parse "0:00"" as "2006""}.
Probably, it doesn't recognize the StartTime and EndTime fields as Time type and uses Timestamp instead. How can I specify that these fields are of the type Time?
Additional information
The following code snippet shows my Building creation:
if err = db.Create(&building).Error; err != nil {
return database.InsertResult{}, err
}
The SQL code of the Building table is as follows:
DROP TABLE IF EXISTS building CASCADE;
CREATE TABLE building(
id SERIAL,
name VARCHAR(255) NOT NULL ,
lon VARCHAR(31) NOT NULL ,
lat VARCHAR(31) NOT NULL ,
start_time TIME NOT NULL ,
end_time TIME NOT NULL ,
PRIMARY KEY (id)
);
While gorm does not support the TIME type directly, you can always create your own type that implements the sql.Scanner and driver.Valuer interfaces to be able to put in and take out time values from the database.
Here's an example implementation which reuses/aliases time.Time, but doesn't use the day, month, year data:
const MyTimeFormat = "15:04:05"
type MyTime time.Time
func NewMyTime(hour, min, sec int) MyTime {
t := time.Date(0, time.January, 1, hour, min, sec, 0, time.UTC)
return MyTime(t)
}
func (t *MyTime) Scan(value interface{}) error {
switch v := value.(type) {
case []byte:
return t.UnmarshalText(string(v))
case string:
return t.UnmarshalText(v)
case time.Time:
*t = MyTime(v)
case nil:
*t = MyTime{}
default:
return fmt.Errorf("cannot sql.Scan() MyTime from: %#v", v)
}
return nil
}
func (t MyTime) Value() (driver.Value, error) {
return driver.Value(time.Time(t).Format(MyTimeFormat)), nil
}
func (t *MyTime) UnmarshalText(value string) error {
dd, err := time.Parse(MyTimeFormat, value)
if err != nil {
return err
}
*t = MyTime(dd)
return nil
}
func (MyTime) GormDataType() string {
return "TIME"
}
You can use it like:
type Building struct {
ID int `json:"id,omitempty"`
Name string `gorm:"size:255" json:"name,omitempty"`
Lon string `gorm:"size:64" json:"lon,omitempty"`
Lat string `gorm:"size:64" json:"lat,omitempty"`
StartTime MyTime `json:"start_time,omitempty"`
EndTime MyTime `json:"end_time,omitempty"`
}
b := Building{
Name: "test",
StartTime: NewMyTime(10, 23, 59),
}
For proper JSON support you'll need to add implementations for json.Marshaler/json.Unmarshaler, which is left as an exercise for the reader 😉
As mentioned in "How to save time in the database in Go when using GORM and Postgresql?"
Currently, there's no support in GORM for any Date/Time types except timestamp with time zone.
So you might need to parse a time as a date:
time.Parse("2006-01-02 3:04PM", "1970-01-01 9:00PM")
I am have come across the same error. It seems like there is a mismatch between type of the column in the database and the Gorm Model
Probably the type of the column in the database is text which you might have set earlier and then changed the column type in gorm model.