For loop while time.Now() is reached - go

Is it possible in Golang to increment a date in a for loop by a given date variable till it reached the current date/ time.Now()
// Start date
t, _ := time.Parse(time.RFC3339, "2018-07-19T12:25:10.8584224+02:00")
// Current date
ct := time.Now()
for d := t; d.Day() == ct.Day(); d = d.AddDate(0, 0, 1) {
// Print all days between start date and current date
fmt.Println(d)
}
I expect that variable d prints out all dates (with time etc.) till it reached the current date

according to godoc: https://golang.org/pkg/time/#Time.Day
func (t Time) Day() int
Day returns the day of the month specified by t.
So comparing d.Day() and ct.Day() is not the right approaches. What if today is "2019-01-01",and you start time is "2018-12-23"?
The right way to compare two time.Time is https://golang.org/pkg/time/#Time.After
func (t Time) After(u Time) bool
func (t Time) Before(u Time) bool
After reports whether the time instant t is after u.
Before reports whether the time instant t is before u.
So #Alex Pliutau's solution is more in common use. But need more careful with today.
package main
import (
"fmt"
"time"
)
func main() {
t, _ := time.Parse(time.RFC3339, "2009-11-02T12:25:10.8584224+02:00")
// truncate to 0:0:0
t = t.Truncate(24 * time.Hour)
fmt.Println("start time is:", t)
// Current date truncate to 0:0:0
ct := time.Now().Truncate(24 * time.Hour)
fmt.Println("now is:", ct)
fmt.Println("---------------")
// for t.Before(ct) { //if you don't want to print the date of today
for !t.After(ct) {
// Print all days between start date and current date
fmt.Println(t.Format("2006-01-02 15:04:05"))
t = t.AddDate(0, 0, 1)
}
}
Output:
start time is: 2009-11-02 02:00:00 +0200 +0200
now is: 2009-11-10 00:00:00 +0000 UTC
---------------
2009-11-02 02:00:00
2009-11-03 02:00:00
2009-11-04 02:00:00
2009-11-05 02:00:00
2009-11-06 02:00:00
2009-11-07 02:00:00
2009-11-08 02:00:00
2009-11-09 02:00:00
2009-11-10 02:00:00
https://play.golang.org/p/iMr7M5W9K4N

get the loop condition right and..
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("Hello, playground")
t, _ := time.Parse(time.RFC3339, "2018-07-19T12:25:10.8584224+02:00")
// Current date
ct := time.Now()
for d := t; d.Day() >= ct.Day(); d = d.AddDate(0, 0, 1) {
// Print all days between start date and current date
fmt.Println(d)
}
}
Hello, playground
2018-07-19 12:25:10.8584224 +0200 +0200
2018-07-20 12:25:10.8584224 +0200 +0200
2018-07-21 12:25:10.8584224 +0200 +0200
2018-07-22 12:25:10.8584224 +0200 +0200
2018-07-23 12:25:10.8584224 +0200 +0200
2018-07-24 12:25:10.8584224 +0200 +0200
2018-07-25 12:25:10.8584224 +0200 +0200
2018-07-26 12:25:10.8584224 +0200 +0200
2018-07-27 12:25:10.8584224 +0200 +0200
2018-07-28 12:25:10.8584224 +0200 +0200
2018-07-29 12:25:10.8584224 +0200 +0200
2018-07-30 12:25:10.8584224 +0200 +0200
2018-07-31 12:25:10.8584224 +0200 +0200
https://play.golang.org/p/yRBTUZKfseG

Based on your comments, you need to actually tell it to Format the date to something of value:
package main
import (
"fmt"
"log"
"time"
)
func main() {
start, err := time.Parse("2006-1-2", "2018-1-1")
if err != nil {
log.Fatal(err)
}
for d := start; d.Month() == start.Month(); d = d.AddDate(0, 0, 1) {
fmt.Println(d.Format("2006-1-2"))
}
}
Here's a simpler version of your code (I used a custom time format, cause I didn't wanna edit the RFC syntax, but ultimately it's the same thing) = I'm also iterating Month for brevity.

package main
import (
"fmt"
"time"
)
func main() {
t, _ := time.Parse(time.RFC3339, "2018-07-19T12:25:10.8584224+02:00")
ct := time.Now()
for t.Before(ct) {
fmt.Println(t)
t.AddDate(0, 0, 1)
}
}

Related

Ticker should not execute if already running

I have some function that has to run periodically. I have used a ticker for this. But if the ticker is already running, and the time interval passes again, it should not execute again.
package main
import (
"fmt"
"time"
)
func main() {
ticker := time.NewTicker(3*time.Second)
flag := 0
defer ticker.Stop()
for {
select {
case t := <-ticker.C:
flag = flag + 1
if (flag % 2 ==0 ) {
time.Sleep(time.Second*4)
}
fmt.Println("Current time: ", t)
}
}
}
https://play.golang.org/p/2xV2MYInn4I
In the playground, the ticker prints every 3 seconds, but every even turn of the ticker the job takes more time than the interval. I expect it to not run then and drop those ticks.
How do I do this?
sleeping inside the same goroutine merely delays execution. ticker meanwhile runs in a separate goroutine. So even if you used a global variable to maintain an execution state - it will not give you your desired result with sleep. However migrating the whole "sleeping" in a separate goroutine yields:
package main
import (
"fmt"
"time"
)
type Tick struct {
ticker *time.Ticker
executing bool
}
func somethingYouWantToDo(tick *Tick, flag *int, t time.Time) {
if tick.executing {
return
}
tick.executing = true
*flag = *flag + 1
if (*flag % 2 ==0 ) {
time.Sleep(time.Second*4)
}
fmt.Println("Current time: ", t)
tick.executing = false
}
func main() {
tick := &Tick{
ticker: time.NewTicker(3*time.Second),
}
flag := 0
defer tick.ticker.Stop()
for {
select {
case t := <-tick.ticker.C:
go somethingYouWantToDo(tick, &flag, t)
}
}
}
// output
// Current time: 2009-11-10 23:00:03 +0000 UTC m=+3.000000001
// Current time: 2009-11-10 23:00:06 +0000 UTC m=+6.000000001
// Current time: 2009-11-10 23:00:12 +0000 UTC m=+12.000000001
// Current time: 2009-11-10 23:00:15 +0000 UTC m=+15.000000001
// Current time: 2009-11-10 23:00:21 +0000 UTC m=+21.000000001
// Current time: 2009-11-10 23:00:24 +0000 UTC m=+24.000000001
// Current time: 2009-11-10 23:00:30 +0000 UTC m=+30.000000001
// Current time: 2009-11-10 23:00:33 +0000 UTC m=+33.000000001
// Current time: 2009-11-10 23:00:39 +0000 UTC m=+39.000000001
// Current time: 2009-11-10 23:00:42 +0000 UTC m=+42.000000001
// Current time: 2009-11-10 23:00:48 +0000 UTC m=+48.000000001
// Current time: 2009-11-10 23:00:51 +0000 UTC m=+51.000000001
// Current time: 2009-11-10 23:00:57 +0000 UTC m=+57.000000001
// Current time: 2009-11-10 23:01:00 +0000 UTC m=+60.000000001
// Current time: 2009-11-10 23:01:06 +0000 UTC m=+66.000000001
// Current time: 2009-11-10 23:01:09 +0000 UTC m=+69.000000001
Try it on the playground
The ticker channel is buffered, which is why you may see multiple triggers right one after the other. You can prevent that by simply transfering the ticker's values to an unbuffered channel (note also that the time.Time value received from the ticker is not the current time but the time of the last tick):
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan time.Time) // unbuffered
ticker := time.NewTicker(3 * time.Second)
defer ticker.Stop()
go func() {
for t := range ticker.C {
select {
case c <- t:
default:
}
}
}()
for flag := 0; flag < 8; flag++ {
<-c
if flag%2 == 0 {
time.Sleep(time.Second * 4)
}
fmt.Println("Current time: ", time.Now())
}
}
// Output:
// Current time: 2020-02-19 12:21:57.095433032 +0100 CET m=+3.000213350
// Current time: 2020-02-19 12:22:04.095585208 +0100 CET m=+10.000365520
// Current time: 2020-02-19 12:22:06.095363327 +0100 CET m=+12.000143680
// Current time: 2020-02-19 12:22:13.095605268 +0100 CET m=+19.000385598
// Current time: 2020-02-19 12:22:15.095371885 +0100 CET m=+21.000152174
// Current time: 2020-02-19 12:22:22.095537562 +0100 CET m=+28.000317857
// Current time: 2020-02-19 12:22:24.095431317 +0100 CET m=+30.000211625
// Current time: 2020-02-19 12:22:31.095524308 +0100 CET m=+37.000304595
Try it on the playground: https://play.golang.org/p/jDe5uJiRVe2

How to update hour, min, sec in golang time?

Ex: How can I update hour in t time?
fmt.Println(t)
//=> 2006-01-02 15:04:05 +0000 UTC
Expect to get: 2006-01-02 00:00:00 +0000 UTC
Edited: similar to: time.Time Round to Day
Use:
t1 := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, t.Nanosecond(), t.Location())
Ref: https://golang.org/pkg/time/#Date
This seems to do it:
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now().UTC()
t = t.Truncate(24 * time.Hour)
fmt.Println(t)
}
https://golang.org/pkg/time#Time.Truncate

time format converted to strftime default format

In the wikipedia entry for Common Log Format, the strftime format is given as:
[10/Oct/2000:13:55:36 -0700] is the date, time, and time zone that the
request was received, by default in strftime format %d/%b/%Y:%H:%M:%S
%z.
When I try using the time.Format function:
package main
import (
"fmt"
"time"
)
func main() {
t, _ := time.Parse(time.UnixDate, "Tue Oct 10 13:55:36 PDT 2000")
fmt.Println(time.Time(t).Format("01/Feb/2006:15:04:05 -0700"))
}
I get the output [10/Feb/2000:13:55:36 +0000], while I was expecting [10/Oct/2000:13:55:36 -0700] (per Wikipedia). What is wrong with my formatting?
I checked that day was a Tuesday and the time zone was -7h (PDT) for that date.
For the Format layout, Jan not Feb. For example,
package main
import (
"fmt"
"time"
)
func main() {
t, err := time.Parse(time.UnixDate, "Tue Oct 10 13:55:36 PDT 2000")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(time.Time(t).Format("01/Jan/2006:15:04:05 -0700"))
}
Output:
10/Oct/2000:13:55:36 +0000
Also, for the time zone, use ParseInLocation,
package main
import (
"fmt"
"time"
)
func main() {
loc, err := time.LoadLocation("America/Los_Angeles")
if err != nil {
fmt.Println(err)
return
}
t, err := time.ParseInLocation(time.UnixDate, "Tue Oct 10 13:55:36 PDT 2000", loc)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(t)
fmt.Println(time.Time(t).Format("01/Jan/2006:15:04:05 -0700"))
}
Playground: https://play.golang.org/p/tBLw5oJSE5t
Output:
2000-10-10 13:55:36 -0700 PDT
10/Oct/2000:13:55:36 -0700

Use timestamp from Mysql in humanize.Time() package

I have a mariaDB database with a timestamp field. I want the values from that field being parsed to time.Time() values. This is possible by adding the ?parseTime=true to the connection string. After fetching a row, I want to use the value (which is time.Time) with humanize.Time(). Unfortunately values within the past 60 minutes are converted by humanize.Time() as 1 hour from now. When I put directly a time.Time() value into humanize.Time(), it gives me x seconds ago.
So I don't know what I'm doing wrong here. I think I need to convert 2017-04-23 14:00:16 +0000 UTC to 2017-04-23 14:00:16.370758048 +0200 CEST, but how?
package main
import (
"fmt"
"log"
"time"
humanize "github.com/dustin/go-humanize"
)
// value from database: 2017-04-23 14:00:16 +0000 UTC
// typical time.Now() value: 2017-04-23 14:00:16.370758048 +0200 CEST
func main() {
layout := "2006-01-02 15:04:05 -0700 MST"
beforeParsing := "2017-04-23 14:00:16 +0000 UTC"
t, err := time.Parse(layout, beforeParsing)
if err != nil {
log.Fatal(err)
}
fmt.Println(t)
fmt.Println(humanize.Time(t))
}

PST to UTC parsing of time in Golang

I am trying to convert the time from PST to UTC timezone but seeing some unexpected result, while IST to UTC is working fine:
package main
import (
"fmt"
"time"
)
func main() {
const longForm = "2006-01-02 15:04:05 MST"
t, err := time.Parse(longForm, "2016-01-17 20:04:05 IST")
fmt.Println(t, err)
fmt.Printf("IST to UTC: %v\n\n", t.UTC())
s, err1 := time.Parse(longForm, "2016-01-17 23:04:05 PST")
fmt.Println(s, err1)
fmt.Printf("PST to UTC: %v\n\n", s.UTC())
}
Output is :
2016-01-17 20:04:05 +0530 IST <nil>
IST to UTC: 2016-01-17 14:34:05 +0000 UTC
2016-01-17 23:04:05 +0000 PST <nil>
PST to UTC: 2016-01-17 23:04:05 +0000 UTC
When parsing is done for IST, it shows +0530, while for PST shows +0000 and in UTC it print same value of HH:MM:SS (23:04:05) as in PST. Am i missing anything here?
The documentation for time.Parse() says:
If the zone abbreviation is unknown, Parse records the time as being in a fabricated location with the given zone abbreviation and a zero offset. This choice means that such a time can be parsed and reformatted with the same layout losslessly, but the exact instant used in the representation will differ by the actual zone offset. To avoid such problems, prefer time layouts that use a numeric zone offset, or use ParseInLocation.
Here is how to use ParseInLocation:
IST, err := time.LoadLocation("Asia/Kolkata")
if err != nil {
fmt.Println(err)
return
}
PST, err := time.LoadLocation("America/Los_Angeles")
if err != nil {
fmt.Println(err)
return
}
const longForm = "2006-01-02 15:04:05 MST"
t, err := time.ParseInLocation(longForm, "2016-01-17 20:04:05 IST", IST)
fmt.Println(t, err)
fmt.Printf("IST to UTC: %v\n\n", t.UTC())
s, err1 := time.ParseInLocation(longForm, "2016-01-17 23:04:05 PST", PST)
fmt.Println(s, err1)
fmt.Printf("PST to UTC: %v\n\n", s.UTC())
Output:
2016-01-17 20:04:05 +0530 IST <nil>
IST to UTC: 2016-01-17 14:34:05 +0000 UTC
2016-01-17 23:04:05 -0800 PST <nil>
PST to UTC: 2016-01-18 07:04:05 +0000 UTC
Full code on the Go Playground
The documentation for time.Parse() says:
If the zone abbreviation is unknown, Parse records the time as being in a fabricated location with the given zone abbreviation and a zero offset. This choice means that such a time can be parsed and reformatted with the same layout losslessly, but the exact instant used in the representation will differ by the actual zone offset. To avoid such problems, prefer time layouts that use a numeric zone offset, or use ParseInLocation.
So, the system doesn't know what "PST" is. For me, the system also doesn't know what IST is. You can check for supported locations like so:
package main
import (
"fmt"
"time"
)
func main() {
for _, name := range []string{"MST", "UTC", "IST", "PST", "EST", "PT"} {
loc, err := time.LoadLocation(name)
if err != nil {
fmt.Println("No location", name)
} else {
fmt.Println("Location", name, "is", loc)
}
}
}
Output on my system:
Location MST is MST
Location UTC is UTC
No location IST
No location PST
Location EST is EST
No location PT

Resources