Why is time in Go printed differently in a struct? - datetime

I'm just starting out with Go, and in the first program I wrote I printed out a struct, which also showed
{wall:0 ext:63533980800 loc:<nil>}
Being puzzled over what that was it seemed to be a type time.Time(), and a google search brought me to this part of the Go source code in which the difference between the "wall clock" and the "monotonic clock" is explained in the comments.
So to test it in isolation I created a new minimalistic program:
package main
import (
"fmt"
"time"
)
type TheStruct struct {
the_time time.Time
}
func main() {
the_struct := TheStruct{time.Now()}
fmt.Println(the_struct)
fmt.Printf("%+v\n", the_struct)
fmt.Println(the_struct.the_time)
fmt.Println()
the_struct_2 := TheStruct{time.Unix(1505099248, 200)}
fmt.Println(the_struct_2)
fmt.Printf("%+v\n", the_struct_2)
fmt.Println(the_struct_2.the_time)
}
which prints out the following:
{{13719544904843884912 534246 0x1140680}}
{the_time:{wall:13719544904843884912 ext:534246 loc:0x1140680}}
2017-09-11 05:08:11.35635032 +0200 CEST m=+0.000534246
{{200 63640696048 0x1140680}}
{the_time:{wall:200 ext:63640696048 loc:0x1140680}}
2017-09-11 05:07:28 +0200 CEST
So I wonder about two things here:
Why is the time if part of a struct printed as wall clock as compared to the more usual datetime notation when printed out separately (using the_struct.the_time)?
Is it a problem that the code in my other program prints out <nil> for the loc? How would I be able to solve that?

The reason why it's not printing the formatted time when in your struct is that String method is not invoked on the unexported fields (refer https://golang.org/pkg/fmt/):
When printing a struct, fmt cannot and therefore does not invoke
formatting methods such as Error or String on unexported fields.
Changing your structure to export fields (capitalizing the first letter) makes it invoke the String method:
package main
import (
"fmt"
"time"
)
type TheStruct struct {
The_time time.Time
}
func main() {
the_struct := TheStruct{time.Now()}
fmt.Println(the_struct)
fmt.Printf("%+v\n", the_struct)
fmt.Println(the_struct.The_time)
fmt.Println()
the_struct_2 := TheStruct{time.Unix(1505099248, 200)}
fmt.Println(the_struct_2)
fmt.Printf("%+v\n", the_struct_2)
fmt.Println(the_struct_2.The_time)
}
Output:
{2009-11-10 23:00:00 +0000 UTC m=+0.000000000}
{The_time:2009-11-10 23:00:00 +0000 UTC m=+0.000000000}
2009-11-10 23:00:00 +0000 UTC m=+0.000000000
{2017-09-11 03:07:28.0000002 +0000 UTC}
{The_time:2017-09-11 03:07:28.0000002 +0000 UTC}
2017-09-11 03:07:28.0000002 +0000 UTC
On playground : https://play.golang.org/p/r0rQKBlpWc

The other answer covers the first part of your question quite well, so I will only cover the second part here.
To put it simply, no, a nil location is not a problem, as acording to the source code for time.Time, a nil location means UTC.
// loc specifies the Location that should be used to
// determine the minute, hour, month, day, and year
// that correspond to this Time.
// The nil location means UTC.
// All UTC times are represented with loc==nil, never loc==&utcLoc.
loc *Location

Related

`foo.Seconds()` (type time.Duration) error - Cannot use 'd.Step.Seconds()' (type float64) as type time.Duration

I'm still really new to go...so,
The crux of my issue can be summed up as this: I'm preparing data to be sent off to a remote API which requires this field to be a time.Duration type, which I was trying to send as a string type of seconds ###s and would time.ParseDuration() it to seconds, however that was a mistake.
type Duration struct {
Duration time.Duration
Step time.Duration
}
// Needs to return a structure containing a duration formatted
// item and an item which is strictly in `seconds` format IE
// `int` or `float` `+` `"s"`.
func getDuration(pr *PromRequest) (Duration, error) {
duration, err := time.ParseDuration(pr.TimeRange)
if err != nil {
return Duration{}, nil
}
timeValue, err := strconv.Atoi(pr.TimeRange[:len(pr.TimeRange)-1])
if err != nil {
return Duration{}, err
}
// convert day value to day in hours
step := time.Duration(int64(24*timeValue) * 60 / 14)
return Duration{
Duration: duration,
Step: step, // <-- should be a time.Duration type...
}, nil
}
// \/\/hatever
func getMetricsWithRange(pr *PromRequest) (model.Value, error) {
d, err := getDuration(pr)
if err != nil {
e := fmt.Errorf("unable to translate received time into proper parsed time signature: %s", err)
fmt.Println(e)
return nil, err
}
...
r := v1.Range{
Start: time.Now().Add(-d.Duration),
End: time.Now(),
Step: d.Step.Seconds(), // <-- error lands here stating it's a float64
}
...
}
** EDIT **
So I think I understand my misunderstanding now. time.Duration() returns a time.Duration type on which one can then send through .Seconds(), which returns a float64.
In the caller, which consumed the returned struct, when I printed the value of the instance variable it would be something NOT time.Duration. I needed it to be in seconds as a time.Duration type in the form of ###s, which I learned time.Duration won't do. Calling .Seconds() on it failed with the error Cannot use 'd.Step.Seconds()' (type float64) as type time.Duration
OK, so my misunderstanding came from a few factors. One: I was really tired. Two: I'm new to go and statically typed languages in general. Three: I believed I needed to send v1.Range.Step in seconds, which was wrong. I took a look at the receiving code which transforms the time.Duration value into seconds itself.
Now, the bigger part of this problem came from the fact that my frontend code was sending a value in days using the letter d in the string. time.ParseDuration() doesn't handle d days so instead of using days I thought I would simply pass a time value in seconds.
Turns out, the easiest way to fix this was to simply send seconds from the frontend. I was never able to get the go code to work right.
Duration.Seconds() returns a float64 value, because the duration value may not be a whole second and it may have decimal digits to represent the exact duration. If the Step variable is to be a duration rounded up to the nearest second, use Duration.Round(time.Second):
...
Step: Step.Round(time.Second)
This will give you a duration that is rounded to a whole second.
If you want to get the seconds value, that's not a duration, that's simply an integer:
...
Step: int(Step.Seconds())
However, in this case the resulting Step is not a duration, but simply an int value giving the number of seconds.

how to convert UTC to India local time using golang

Mentioning the code below
loc, _ := time.LoadLocation("Asia/Kolkata")
now := time.Now().In(loc)
fmt.Println("Location : ", loc, " Time : ", now)
visit.Time = now
getting UTC time but i need to get IST in my datastore
In the Go Playground, this is working as expected.
About the Playground
The Go Playground is a web service that runs on golang.org's servers.
The service receives a Go program, compiles, links, and runs the
program inside a sandbox, then returns the output.
There are limitations to the programs that can be run in the
playground:
In the playground the time begins at 2009-11-10 23:00:00 UTC
(determining the significance of this date is an exercise for the
reader). This makes it easier to cache programs by giving them
deterministic output.
The article "Inside the Go Playground" describes how the playground is
implemented.
package main
import (
"fmt"
"time"
)
func main() {
loc, _ := time.LoadLocation("Asia/Kolkata")
now := time.Now().In(loc)
fmt.Println("Location : ", loc, " Time : ", now)
}
Playground: https://play.golang.org/p/l8t3BnQATg7
Output:
Location : Asia/Kolkata Time : 2009-11-11 04:30:00 +0530 IST
The correct argument for IST is "Asia/Calcutta" not "Asia/Kolkata". Here is the complete list https://golang.org/src/time/zoneinfo_abbrs_windows.go

Assign value returned from function to pointer

In Go, how do you assign a value returned by a function call to a pointer?
Consider this example, noting that time.Now() returns a time.Time value (not pointer):
package main
import (
"fmt"
"time"
)
type foo struct {
t *time.Time
}
func main() {
var f foo
f.t = time.Now() // Fail line 15
f.t = &time.Now() // Fail line 17
tmp := time.Now() // Workaround
f.t = &tmp
fmt.Println(f.t)
}
These both fail:
$ go build
# _/home/jreinhart/tmp/go_ptr_assign
./test.go:15: cannot use time.Now() (type time.Time) as type *time.Time in assignment
./test.go:17: cannot take the address of time.Now()
Is a local variable truly required? And doesn't that incur an unnecessary copy?
The local variable is required per the specification.
To get the address of a value, the calling function must copy the return value to addressable memory. There is a copy, but it's not extra.
Go programs typically work with time.Time values.
A *time.Time is sometimes used situations where the application wants to distinguish between no value and other time values. Distinguishing between a SQL NULL and a valid time is an example. Because the zero value for a time.Time is so far in the past, it's often practical to use the zero value to represent no value. Use the IsZero() method to test for a zero value.

How do I convert a chrono `DateTime<UTC>` instance to `DateTime<Local>`?

My goal is to convert utc into loc:
use chrono::{Local, UTC, TimeZone};
let utc = chrono::UTC::now();
let loc = chrono::Local::now();
println!("{:?}", utc);
println!("{:?}", loc);
println!("{:?}", utc.with_timezone(&Local));
println!("{:?}", Local.from_utc_datetime(&utc.naive_local()));
... which produced the following output:
2015-02-26T16:22:27.873593Z
2015-02-26T17:22:27.873663+01:00
2015-02-26T15:22:27.873593+00:00
2015-02-26T15:22:27.873593+00:00
The loc time shown in the second row is what I want to see when converting utc.
How do I properly convert a DateTime<UTC> instance to DateTime<Local>?
Meta
I am using chrono 0.2.2. In the DateTime.from_utc method it's even telling me I should use the TimeZone trait. However, I am missing something.
Starting with chrono 0.4.7 you can convert them between with using from trait in a simpler way:
use chrono::prelude::*;
fn main() {
let utc = Utc::now();
let local = Local::now();
let converted: DateTime<Local> = DateTime::from(utc);
}
Oops, thank you for reporting. This is a bug and registered as the issue #26. This should be fixed in Chrono 0.2.3.
Besides from the bug, utc.with_timezone(&Local) is indeed a correct way to convert to the local time. There is an important identity that utc.with_timezone(&Local).with_timezone(&UTC) should be equal to utc (except for the exceptional case, where the local time zone has been changed).

Obtaining a Unix Timestamp in Go Language (current time in seconds since epoch)

I have some code written in Go which I am trying to update to work with the latest weekly builds. (It was last built under r60). Everything is now working except for the following bit:
if t, _, err := os.Time(); err == nil {
port[5] = int32(t)
}
Any advice on how to update this to work with the current Go implementation?
import "time"
...
port[5] = time.Now().Unix()
If you want it as string just convert it via strconv:
package main
import (
"fmt"
"strconv"
"time"
)
func main() {
timestamp := strconv.FormatInt(time.Now().UTC().UnixNano(), 10)
fmt.Println(timestamp) // prints: 1436773875771421417
}
Another tip. time.Now().UnixNano()(godoc) will give you nanoseconds since the epoch. It's not strictly Unix time, but it gives you sub second precision using the same epoch, which can be handy.
Edit: Changed to match current golang api
Building on the idea from another answer here, to get a human-readable interpretation, you can use:
package main
import (
"fmt"
"time"
)
func main() {
timestamp := time.Unix(time.Now().Unix(), 0)
fmt.Printf("%v", timestamp) // prints: 2009-11-10 23:00:00 +0000 UTC
}
Try it in The Go Playground.

Resources