I'm using C# my entire life and now trying out GO. How do I find the lower time value between two time structs?
import (
t "time"
"fmt"
)
func findTime() {
timeA, err := t.Parse("01022006", "08112016")
timeB, err := t.Parse("01022006", "08152016")
Math.Min(timeA.Ticks, timeB.Ticks) // This is C# code but I'm looking for something similar in GO
}
You can use the Time.Before method to test if a time is before another:
timeA, err := time.Parse("01022006", "08112016")
timeB, err := time.Parse("01022006", "08152016")
var min time.Time
if timeA.Before(timeB) {
min = timeA
} else {
min = timeB
}
Related
RFC-3339 Section 4.3 (https://www.rfc-editor.org/rfc/rfc3339#section-4.3) defines the -00:00 offset as the following, which is different than Z or +00:00.
4.3. Unknown Local Offset Convention
If the time in UTC is known, but the offset to local time is unknown,
this can be represented with an offset of "-00:00". This differs
semantically from an offset of "Z" or "+00:00", which imply that UTC
is the preferred reference point for the specified time. RFC2822
[IMAIL-UPDATE] describes a similar convention for email.
However, I'm not sure how to represent this in Go. When I parse a time with -00:00 and format it, I get a Z offset. For example:
Input: 2018-01-01T00:00:00-00:00
Output: 2018-01-01T00:00:00Z
Here's some example code (https://play.golang.org/p/CVmNnhaSiiT):
package main
import (
"fmt"
"time"
)
func main() {
t := "2018-01-01T00:00:00-00:00"
fmt.Println("Input " + t)
p, err := time.Parse(time.RFC3339, t)
if err != nil {
fmt.Println(err)
} else {
t2 := p.Format(time.RFC3339)
fmt.Println("Output " + t2)
}
}
Package time
import "time"
RFC3339, RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for
formatting; when used with time.Parse they do not accept all the time
formats permitted by the RFCs.
Go does not accept all the time formats permitted by the RFCs.
The Go time.Time type uses integers which, unlike floating-point, have no concept of plus and minus zero. The results for parsing offsets of -00:00 and +00:00 are identical.
For example,
package main
import (
"fmt"
"time"
)
func main() {
var err error
var minus, plus time.Time
t := "2018-01-01T00:00:00-00:00"
minus, err = time.Parse(time.RFC3339, t)
if err != nil {
fmt.Println(err)
}
t = "2018-01-01T00:00:00+00:00"
plus, err = time.Parse(time.RFC3339, t)
if err != nil {
fmt.Println(err)
}
fmt.Println(minus, plus, minus.Equal(plus), minus == plus)
}
Playground: https://play.golang.org/p/Urf8VlKYoMH
Output:
2018-01-01 00:00:00 +0000 UTC 2018-01-01 00:00:00 +0000 UTC true true
PeterSO's answer is perfect IMHO. If you need to act differently based on the information that the offset is unknown, then this might help you.
You can build your own time data type:
type MyTime struct {
// based on time.Time so we can do all normal time.Time stuff
time.Time
offsetUnknown bool
}
func ParseRFC3339(s string) (MyTime, error) {
time, err := time.Parse(time.RFC3339, s)
if err != nil {
return MyTime{}, err
}
return MyTime{
Time: time,
// maybe this condition needs improvement in case of false positives
offsetUnknown: strings.Contains(s, "-00:00"),
}, nil
}
Any functions you need to behave differently based on offsetUnknown you can then override on the MyTime struct. Here one example:
func (s MyTime) Format(layout string) string {
out := s.Time.Format(layout)
// again this is probably not the best solution
if layout == time.RFC3339 && s.offsetUnknown {
out = strings.Replace(out, "+00:00", "-00:00", -1)
}
return out
}
I'm expecting these two time.Time instances are the same. But, I'm not sure why I got the compare result is false.
package main
import (
"fmt"
"time"
)
func main() {
t := int64(1497029400000)
locYangon, _ := time.LoadLocation("Asia/Yangon")
dt := fromEpoch(t).In(locYangon)
locYangon2, _ := time.LoadLocation("Asia/Yangon")
dt2 := fromEpoch(t).In(locYangon2)
fmt.Println(dt2 == dt)
}
func fromEpoch(jsDate int64) time.Time {
return time.Unix(0, jsDate*int64(time.Millisecond))
}
Playground
If I change "Asia/Yangon" to "UTC", they are the same.
package main
import (
"fmt"
"time"
)
func main() {
t := int64(1497029400000)
locYangon, _ := time.LoadLocation("UTC")
dt := fromEpoch(t).In(locYangon)
locYangon2, _ := time.LoadLocation("UTC")
dt2 := fromEpoch(t).In(locYangon2)
fmt.Println(dt2 == dt)
}
func fromEpoch(jsDate int64) time.Time {
return time.Unix(0, jsDate*int64(time.Millisecond))
}
Playground
Note: I'm aware of Equal method (in fact, I fixed with Equal method.) But after more testing, I found some interesting case which is "UTC" location vs "Asia/Yangon" location. I'm expecting either both equal or both not equal.
Update: Add another code snippet with "UTC".
Update2: Update title to be more precise (I hope it will help to avoid duplication)
LoadLocation seems to return a pointer to a new value every time.
Anyway, the good way to compare dates is Equal:
fmt.Println(dt2.Equal(dt))
Playground: https://play.golang.org/p/9GW-LSF0wg.
I started to do programming contests in go (just to learn the language) and to my surprise found that
var T int
fmt.Scanf("%d", &T)
is unimaginably slow. How slow? To read 10^5 integers it take me 2.5 seconds (in comparison python does it in 0.8 secs).
So why is it so slow and how should I properly read int, uint64 and float64?
If you have only the integer as input, this should be faster (not tested though)
package main
import (
"io/ioutil"
"log"
"os"
"strconv"
)
func read() (int64, error) {
b, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return 0, err
}
// use strconv.ParseUint and strconv.ParseFloat in a similar way
return strconv.ParseInt(string(b[:len(b)-1]), 10, 0)
}
func main() {
i, err := read()
if err != nil {
log.Fatal(err)
}
println(i)
}
run it like this
echo 123 | go run main.go
for interactive input, you might want to use bufio.NewReader, see How to read input from console line?
I'm trying to loop through files in a directory and compare their ModTime against a certain date in order to delete older files.
I'm using ioutil.ReadDir() to get the files but I'm stuck with how to retrieve the ModTime of each file.
Thanks
The return from ioutil.ReadDir is ([]os.FileInfo, error). You would simply iterate the []os.FileInfo slice and inspect the ModTime() of each. ModTime() returns a time.Time so you can compare in any way you see fit.
package main
import (
"fmt"
"io/ioutil"
"log"
"time"
)
var cutoff = 1 * time.Hour
func main() {
fileInfo, err := ioutil.ReadDir("/tmp")
if err != nil {
log.Fatal(err.Error())
}
now := time.Now()
for _, info := range fileInfo {
if diff := now.Sub(info.ModTime()); diff > cutoff {
fmt.Printf("Deleting %s which is %s old\n", info.Name(), diff)
}
}
}
Does anyone know how to check for a file access date and time? The function returns the modified date and time and I need something that compares the accessed date time to the current date and time.
You can use os.Stat to get a FileInfo struct which also contains the last access time (as well as the last modified and the last status change time).
info, err := os.Stat("example.txt")
if err != nil {
// TODO: handle errors (e.g. file not found)
}
// info.Atime_ns now contains the last access time
// (in nanoseconds since the unix epoch)
After that, you can use time.Nanoseconds to get the current time (also in nanoseconds since the unix epoch, January 1, 1970 00:00:00 UTC). To get the duration in nanoseconds, just subtract those two values:
duration := time.Nanoseconds() - info.Atime_ns
By casting os.FileInfo to *syscall.Stat_t:
package main
import ( "fmt"; "log"; "os"; "syscall"; "time" )
func main() {
for _, arg := range os.Args[1:] {
fileinfo, err := os.Stat(arg)
if err != nil {
log.Fatal(err)
}
atime := fileinfo.Sys().(*syscall.Stat_t).Atim
fmt.Println(time.Unix(atime.Sec, atime.Nsec))
}
}
Alternatively, after the Stat you can also do
statinfo.ModTime()
Also you can use Format() on it, should you need it eg for a webserver
see https://gist.github.com/alexisrobert/982674
For windows
syscall.Win32FileAttributeData
info, _ := os.Stat("test.txt")
fileTime := info.Sys().(*syscall.Win32FileAttributeData).LastAccessTime
aTime := time.Unix(0, fileTime.Nanoseconds())
Example
package main
import (
"fmt"
"log"
"os"
"syscall"
"time"
)
func main() {
info, _ := os.Stat("./test.txt")
fileTime := info.Sys().(*syscall.Win32FileAttributeData).LastAccessTime
// _ = info.Sys().(*syscall.Win32FileAttributeData).CreationTime
// _ = info.Sys().(*syscall.Win32FileAttributeData).LastWriteTime
fileAccessTime := time.Unix(0, fileTime.Nanoseconds())
// Compare
// t2, _ := time.Parse("2006/01/02 15:04:05 -07:00:00", "2023/02/08 13:18:00 +08:00:00")
now := time.Now()
log.Println(fileAccessTime)
log.Println(now.Add(-20 * time.Minute))
if fileAccessTime.After(now.Add(-20 * time.Minute)) {
fmt.Println("You accessed this file 20 minutes ago.")
}
}
Linux
see this answer