prevent json.Marshal time.Time removing trailing zeros - go

I have code similar to the following
package main
import (
"fmt"
"time"
"encoding/json"
)
type Message struct {
Time time.Time `json:"timestamp,omitempty"`
}
func main() {
t, _ := time.Parse("2006-01-02T15:04:05.999Z07:00", "2017-05-01T15:04:05.630Z")
msg := Message{
Time: t,
}
bs, _ := json.Marshal(msg)
fmt.Println(string(bs[:]))
}
This prints
{"timestamp":"2017-05-01T15:04:05.63Z"}
How can I make json marshalling keep the trailing 0? I.e., to print this?
{"timestamp":"2017-05-01T15:04:05.630Z"}
Edit:
Here's the playground https://play.golang.org/p/9p3kWeiwu2

time.Time always marshals to RFC 3339, only including sub-second precision if present: https://golang.org/pkg/time/#Time.MarshalJSON
You can write your own custom version using a named time.Time type, or you can define a custom marshal function for your structure, or you can make your structure hold a string in that place instead. In any case, if you want to use the same format, but including trailing zeros, you need to use a modified version of the RFC3339Nano constant.
Its value is: "2006-01-02T15:04:05.999999999Z07:00".
The 9's at the end mean "include until the rightmost non-zero value, omit after that". If you change those 9's to 0's, it will always include them. For example, if you always want millisecond precision (and nothing after that, regardless of whether it's non-zero or not), you would use:
"2006-01-02T15:04:05.000Z07:00"
If you feed that to Format() on your time.Time value, you'll get out the string you want, and can thus include it in the JSON.
Functioning example: https://play.golang.org/p/oqwnma6odw

Related

How to convert the string representation of a Terraform set of strings to a slice of strings

I've a terratest where I get an output from terraform like so s := "[a b]". The terraform output's value = toset([resource.name]), it's a set of strings.
Apparently fmt.Printf("%T", s) returns string. I need to iterate to perform further validation.
I tried the below approach but errors!
var v interface{}
if err := json.Unmarshal([]byte(s), &v); err != nil {
fmt.Println(err)
}
My current implementation to convert to a slice is:
s := "[a b]"
s1 := strings.Fields(strings.Trim(s, "[]"))
for _, v:= range s1 {
fmt.Println("v -> " + v)
}
Looking for suggestions to current approach or alternative ways to convert to arr/slice that I should be considering. Appreciate any inputs. Thanks.
Actually your current implementation seems just fine.
You can't use JSON unmarshaling because JSON strings must be enclosed in double quotes ".
Instead strings.Fields does just that, it splits a string on one or more characters that match unicode.IsSpace, which is \t, \n, \v. \f, \r and .
Moeover this works also if terraform sends an empty set as [], as stated in the documentation:
returning [...] an empty slice if s contains only white space.
...which includes the case of s being empty "" altogether.
In case you need additional control over this, you can use strings.FieldsFunc, which accepts a function of type func(rune) bool so you can determine yourself what constitutes a "space". But since your input string comes from terraform, I guess it's going to be well-behaved enough.
There may be third-party packages that already implement this functionality, but unless your program already imports them, I think the native solution based on the standard lib is always preferrable.
unicode.IsSpace actually includes also the higher runes 0x85 and 0xA0, in which case strings.Fields calls FieldsFunc(s, unicode.IsSpace)
package main
import (
"fmt"
"strings"
)
func main() {
src := "[a b]"
dst := strings.Split(src[1:len(src)-1], " ")
fmt.Println(dst)
}
https://play.golang.org/p/KVY4r_8RWv6

Parsefloat give output in scientific format in golang

i am trying to parse this string "7046260" using Parsefloat function in golang , but i am getting output in scientific format 7.04626e+06. i want the output in the format 7046260. how to get this?
package main
import (
"fmt"
"strconv"
)
func main() {
Value := "7046260"
Fval, err := strconv.ParseFloat(Value, 64)
if err == nil {
fmt.Println(Fval)
}
}
ouput :- 7.04626e+06
Parsefloat give output in scientific format in golang
i am trying to parse this string "7046260" using Parsefloat function in golang , but i am getting output in scientific format 7.04626e+06. i want the output in the format 7046260
You're confusing the floating-point value's (default) formatted output with its internal representation.
ParseFloat is working fine.
You just need to specify an output format:
See the fmt package documentation.
Use Printf to specify a format-string.
Use the format %.0f to instruct Go to print the value as-follows:
% marks the start of a placeholder.
. denotes default width (i.e. don't add leading or trailing zeroes).
0 denotes zero radix precision (i.e. don't print any decimal places, even if the value has them)
f denotes the end of the placeholder, and that the placeholder is for a floating-point value.
I have a few other recommendations:
Local variables in Go should use camelCase, not PascalCase. Go does not encourage the use of snake_case.
You should check err != nil after each nil-returning function returns and either fail-fast (if appropriate), pass the error up (and optionally log it), or handle it gracefully.
When working with floating-point numbers, you should be aware of NaN's special status. The IsNaN function is the only way to correctly check for NaN values (because ( aNaNValue1 == math.NaN ) == false).
The same applies in all languages that implement IEEE-754, including Java, JavaScript, C, C#.NET and Go.
Like so:
package main
import (
"fmt"
"strconv"
"math"
"log"
)
func main() {
numberText := "7046260"
numberFloat, err := strconv.ParseFloat(numberText, 64)
if err != nil {
log.Fatal(err)
}
if math.IsNaN(numberFloat) {
log.Fatal("NaN value encountered")
}
fmt.Printf("%.0f",numberFloat)
fmt.Println()
}

How does an untyped constant '\n' get converted into a byte when passed as method arg?

I was watching this talk given at FOSDEM '17 about implementing "tail -f" in Go => https://youtu.be/lLDWF59aZAo
In the author's initial example program, he creates a Reader using a file handle, and then uses the ReadString method with delimiter '\n' to read the file line by line and print its contents. I usually use Scanner, so this was new to me.
Program below | Go Playground Link
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
fileHandle, err := os.Open("someFile.log")
if err != nil {
log.Fatalln(err)
return
}
defer fileHandle.Close()
reader := bufio.NewReader(fileHandle)
for {
line, err := reader.ReadString('\n')
if err != nil {
log.Fatalln(err)
break
}
fmt.Print(line)
}
}
Now, ReadString takes a byte as its delimiter argument[https://golang.org/pkg/bufio/#Reader.ReadString]
So my question is, how in the world did '\n', which is a rune, get converted into a byte? I am not able to get my head around this. Especially since byte is an alias for uint8, and rune is an alias for int32.
I asked the same question in Gophers slack, and was told that '\n' is not a rune, but an untyped constant. If we actually created a rune using '\n' and passed it in, the compilation would fail. This actually confused me a bit more.
I was also given a link to a section of the Go spec regarding Type Identity => https://golang.org/ref/spec#Type_identity
If the program is not supposed to compile if it were an actual rune, why does the compiler allow an untyped constant to go through? Isn't this unsafe behaviour?
My guess is that this works due to a rule in the Assignability section in the Go spec, which says
x is an untyped constant representable by a value of type T.
Since '\n' can indeed be assigned to a variable of type byte, it is therefore converted.
Is my reasoning correct?
TL;DR Yes you are correct but there's something more.
'\n' is an untyped rune constant. It doesn't have a type but a default type which is int32 (rune is an alias for int32). It holds a single byte representing the literal "\n", which is the numeric value 10:
package main
import (
"fmt"
)
func main() {
fmt.Printf("%T %v %c\n", '\n', '\n', '\n') // int32 10 (newline)
}
https://play.golang.org/p/lMjrTFDZUM
The part of the spec that answers your question lies in the § Calls (emphasis mine):
Given an expression f of function type F,
f(a1, a2, … an)
calls f with arguments a1, a2, … an. Except for one
special case, arguments must be single-valued expressions assignable
to the parameter types of F and are evaluated before the function is
called.
"assignable" is the key term here and the part of the spec you quoted explains what it means. As you correctly guessed, among the various rules of assignability, the one that applies here is the following:
x is an untyped constant representable by a value of type T.
In our case this translates to:
'\n' is an untyped (rune) constant representable by a value of type byte
The fact that '\n' is actually converted to a byte when calling ReadString() is more apparent if we try passing an untyped rune constant wider than 1 byte, to a function that expects a byte:
package main
func main() {
foo('α')
}
func foo(b byte) {}
https://play.golang.org/p/W0EUZppWHH
The code above fails with:
tmp/sandbox120896917/main.go:9: constant 945 overflows byte
That's because 'α' is actually 2 bytes, which means it cannot be converted to a value of type byte (the maximum integer a byte can hold is 255 while 'α' is actually 945).
All this is explained in the official blog post, Constants.
Yes, your reading is correct. Spec: Assignability section applies here as the value you want to pass must be assignable to the type of the parameter.
When you pass the value '\n', that is an untyped constant specified by a rune literal. It represents a number equal to the Unicode code of the '\n' character (which is 10 by the way). The rule you quoted applies here:
x is an untyped constant representable by a value of type T.
Constants have a default type, which will be used when a type is "missing" from the context where the value is used. Such an example is the short variable declaration:
r := '\n'
fmt.Printf("%T", r)
The default type of a rune literal is that: rune. The above code prints int32 because the rune type is an alias for int32 (they are "identical", interchangable). Try it on the Go Playground.
Now if you try to pass the variable r to a function which expects a value of type byte, it is a compile time error, because this case matches none of the assignability rules. You need explicit type conversion to make such a case work:
r := '\n'
line, err := reader.ReadString(byte(r))
See related blog posts and questions:
Spec: Constants
The Go Blog: Constants
Defining a variable in Go programming language
Custom type passed to function as a parameter
Why do these two float64s have different values?
Does go compiler's evaluation differ for constant expression and other expression

Struct field names starting with a string

I have a go struct and I need to work with one of the fields. However I am starting with a string. How do I case it to get the field itself.
package main
import "fmt"
func main() {
type Point struct{
x int
y int
}
pt := Point{x:2, y:3}
a := "x"
fmt.Printf("%s", pt.a)
}
Since a = "x" I am expecting pt.x = 2. Here's the error message it prints out. I am definitely starting with a string so I can't just remove the quotation marks.
$ go run point.go
# command-line-arguments
./point.go:14: pt.a undefined (type Point has no field or method a)
If you need to access a field whose name is given as a string, you have no choice but to use reflection. Go ain't Python. :-)
This blog has a nice explanation.
Here is the reflect package documentation.
But note that reflection should usually be used as a last resort only. It removes the static type safety and is detrimental for performance.
What are you really looking for? There may be a way to address your requirements without using reflection. For example, if you don't need methods attached to your struct, you could use map[string]int.

What exactly does .(data_type) method called/do?

I came a cross a piece of code that used .(string) method. Not knowing what this is called I had difficulties searching for it.
Here is my try to understand it:
package main
import "fmt"
import "reflect"
func main(){
var b interface{}
b = "silly"
fmt.Println(reflect.TypeOf(b.(string))) // we know that b
// is a string
// at compile time
fmt.Println(reflect.TypeOf(b)) // we do not
}
Result:
string
string
However, I think that reflect.TypeOf takes place at run time, while .(string) would tell the compiler that b is indeed a string, and this could be used to tell the compiler that a variable is of certain type. Is my understanding right?
goplayground
b.(string) is called a type assertion. As written in Effective Go:
A type assertion takes an interface value and extracts from it a value of the specified explicit type.
So, yes, the value you get from a type assertion is not an interface value, but is of the explicit type. You can also test if the type assertion was successful by adding an untyped boolean value:
s, ok := b.(string) // s is of type string
if !ok {
// b did not contain a value of type string!
}
Edit:
To explain further to clear out any possible misunderstanding:
A type assertion doesn't "tell Go that b is a string" as you suggested. What it does is that it will, in run time, try to extract a string from b, and panic if b contains some other type (unless assigning the optional bool value).
The value that you get from the assertion will indeed be of type string, allowing you to do things like slicing (you cannot slice an interface value) or checking its len.
The previous answer is correct. But I submit this as more like what happens in practice. The .(type) syntax is usually used with type names in the cases of a switch. In this example, I (integer expr), B (bool expr), and Bop (binary op) are type names.
func commute (e Expr) (r Expr, d bool) {
switch exp:= e.(type) {
case I: r,d = exp,false
case B: r,d = exp,false
case Bop: r,d = Bop{exp.op, exp.right, exp.left},true
default: r,d = e,false
}
return
}
This isn't unsafe like a C cast, because inside the case statement you are guaranteed to have the matching type. I see this quite a bit when reading a channel, where the type of the channel is an interface that all the cases implement.

Resources