I am trying to trigger a worker at certain hour. The thing is that I need to know what is the relative hour of the server for that hour. Clients want to trigger the worker at 8pm everyday in Los Angeles Time, so I have to make it the enough dynamic that it takes the server hour, calculate what is the equivalent for that hour in Los Angeles. I am also using carbon, but is there any built-in function for that? Or is there any know routine to deal with it?
time.LoadLocation and time.In are the two functions you need. The below code is copied and modified from time.LoadLocation example:
func main() {
location, err := time.LoadLocation("America/Los_Angeles")
if err != nil {
panic(err)
}
timeInUTC := time.Date(2018, 8, 30, 12, 0, 0, 0, time.UTC)
fmt.Println(timeInUTC.In(location))
now := time.Now()
timeThere := time.Date(now.Year(), now.Month(), now.Day(), 8, 0, 0, 0, location)
timeHere := timeThere.In(time.Now().Location())
fmt.Println(timeHere)
}
Related
Im trying to rest a month in a date in golang i have this example for march an February:
date := time.Date(2023, time.March, 31, 0, 0, 0, 0, time.UTC)
then a make this:
period := date.AddDate(0, -1, -0)
but the program give me:
original date: 2023-03-31 00:00:00 +0000 UTC
date after rest: 2023-03-03 00:00:00 +0000 UTC
And I expect:
2023-02-28 00:00:00 +0000 UTC
at the same time I want that this rest work for every month dynamically.
Thanks.
Just as the automatically transform that comes with go annoys you, you could also take advantage of this.
The trick is how to get the number of days in the previous month.
// as there is no 0 day, it means the last day of the previous mouth
totDay := time.Date(y, m, 0, 0, 0, 0, 0, time.UTC).Day()
The complete code is as follows:
package main
import (
"fmt"
"time"
)
func previousMouth(t time.Time) time.Time {
y, m, d := t.Date()
curTotDay := time.Date(y, m+1, 0, 0, 0, 0, 0, time.UTC).Day()
totDay := time.Date(y, m, 0, 0, 0, 0, 0, time.UTC).Day()
if d == curTotDay {
d = totDay
}
return time.Date(y, m-1, d, 0, 0, 0, 0, time.UTC)
}
func main() {
date := time.Date(2023, time.March, 31, 0, 0, 0, 0, time.UTC)
fmt.Println(previousMouth(date))
}
Run it online: goplayground.
As others have mentioned in the comments, you cannot go back exactly one month from 31 March. You would end up at 31 February, but that date doesn't exist and is normalised to 3 March.
You can go back to the last day of the previous month, but you would get the same result if you started at 28 March, 29 March, 30 March or 31 March.
But if that is what you want, you can go back (or forward) any number of months, while clipping the day to remain within the number of days in that month.
func firstDayOfMonth(date time.Time) time.Time {
return date.AddDate(0, 0, -date.Day()+1)
}
func daysInMonth(date time.Time) int {
return date.AddDate(0, 1, -date.Day()).Day()
}
func AddMonthsClipped(date time.Time, months int) time.Time {
firstDate := firstDayOfMonth(date)
firstAdded := firstDate.AddDate(0, months, 0)
addDays, maxDays := date.Day(), daysInMonth(firstAdded)
if addDays > maxDays {
addDays = maxDays
}
return firstAdded.AddDate(0, 0, addDays-1)
}
func main() {
date := time.Date(2023, time.March, 31, 0, 0, 0, 0, time.UTC)
fmt.Println(AddMonthsClipped(date, -1))
}
Go Playground: https://go.dev/play/p/JEihMdM0CHe
I found the answer:
package main
import (
"fmt"
"time"
)
func main() {
date := time.Date(2023, time.March, 31, 0, 0, 0, 0, time.UTC)
year, month, _ := date.Date()
endOfLastMonth := time.Date(year, month, 0, 0, 0, 0, 0, date.Location())
fmt.Println("This month: ", date)
fmt.Println("Lasth Month: ", endOfLastMonth)
}
Here the playground: https://go.dev/play/p/iTDFgtdOT9y
After working and working with the date, i made this. Thanks you all
I am trying to construct a GoLang time.Date() instance from the input I get; something like:
time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
Where 'year' 'month' and 'day' are read from a file.
It works fine for most of the cases, however if I pass "2000-01-32" it automatically interprets as "2000-02-01" Example in The Go Playground.
Is there a way to force returning error instead of carry over the day in a case like abovr?
Thanks.
Not directly but you can compare parsed value to given parameters. Unless normalized, they should be same.
func parse(year, month, day int) (time.Time, bool) {
t := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
y, m, d := t.Date()
return t, y == year && int(m) == month && d == day
}
In action: https://play.golang.org/p/UJYszuyJwnx
d := make([]byte, 4096)
conn.Read(d)
I created a fixed array to get data from the socket.
But I want to get the data in a flexible size rather than a fixed size.
The reason is that i need to unmarshal the data received from the socket, but the data is fixed in size, so calling the unmarshal function will not work.
So what I want to ask is how to get the data from the socket in a flexible size or how to delete empty values from a fixed size.
ex)
data := make([]byte, 4096)
conn.Read(data)
fmt.Println(len(data)) ===> 105 (Actual data length)
or
data([4, 128, 16, 8, 7, 0, 0, 0, 0, 7, 9, 128, 0...])
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
data([4, 128, 16, 8, 7, 0, 0, 0, 0, 7, 9, 128])
For example,
data := make([]byte, 0, 4096)
n, err := conn.Read(data[:cap(data)])
data = data[:n]
if err != nil {
// handle error
}
fmt.Println(len(data))
I have a file with about 100gb with a word:tag per line. I want to index these on word to easily get the list of tags for a given word.
I wanted to save this on boltdb (mainly to checkout boltdb) but random write access is bad so I was aiming to index the file in some other way first, then moving all of it to boltdb without need to check for duplicates or de/serialisation of the tag list
So, for reference, if I simply read the file into memory (discarding data), I get about 8 MB/s.
If I write to boltdb files using code such as
line := ""
linesRead := 0
for scanner.Scan() {
line = scanner.Text()
linesRead += 1
data := strings.Split(line, ":")
err = bucket.Put([]byte(data[0]), []byte(data[1]))
logger.FatalErr(err)
// commit on every N lines
if linesRead % 10000 == 0 {
err = tx.Commit()
logger.FatalErr(err)
tx, err = db.Begin(true)
logger.FatalErr(err)
bucket = tx.Bucket(name)
}
}
I get about 300 Kb/s speed and this is not even complete (as it's not adding tag to each word, only stores the last occurrence). So adding the array and JSON serialisation would definitely lower that speed...
So I gave mongodb a try
index := mgo.Index{
Key: []string{"word"},
Unique: true,
DropDups: false,
Background: true,
Sparse: true,
}
err = c.EnsureIndex(index)
logger.FatalErr(err)
line := ""
linesRead := 0
bulk := c.Bulk()
for scanner.Scan() {
line = scanner.Text()
data := strings.Split(line, ":")
bulk.Upsert(bson.M{"word": data[0]}, bson.M{"$push": bson.M{"tags": data[1]}})
linesRead += 1
if linesRead % 10000 == 0 {
_, err = bulk.Run()
logger.FatalErr(err)
bulk = c.Bulk()
}
}
And I get about 300 Kb/s as well (though Upsert and $push here handle appending to the list).
I tried with a local MySQL instance as well (indexed on word) but speed was like 30x slower...
I'm looking for documentation on the Max time.Time in go.
Other languages make it explicit, for example in C#: http://msdn.microsoft.com/en-us/library/system.datetime.maxvalue(v=vs.110).aspx
public static readonly DateTime MaxValue
The value of this constant is equivalent to 23:59:59.9999999, December
31, 9999, exactly one 100-nanosecond tick before 00:00:00, January 1,
10000.
What is the maximum time.Time in Go? Is it documented somewhere?
time.Time in go is stored as an int64 plus a 32-bit nanosecond value, but if you use #JimB's answer you will trigger an integer overflow on the sec component and comparisons like time.Before() will not work.
This is because time.Unix(sec, nsec) adds an offset of 62135596800 seconds to sec that represents the number of seconds between the year 1 (zero time in Go) and 1970 (zero time in Unix).
#twotwotwo's playground example makes this clear in http://play.golang.org/p/i6S_T4-X3v but here is a distilled version.
// number of seconds between Year 1 and 1970 (62135596800 seconds)
unixToInternal := int64((1969*365 + 1969/4 - 1969/100 + 1969/400) * 24 * 60 * 60)
// max1 gets time.Time struct: {-9223371974719179009 999999999}
max1 := time.Unix(1<<63-1, 999999999)
// max2 gets time.Time struct: {9223372036854775807 999999999}
max2 := time.Unix(1<<63-1-unixToInternal, 999999999)
// t0 is definitely before the year 292277026596
t0 := time.Date(2015, 9, 16, 19, 17, 23, 0, time.UTC)
// t0 < max1 doesn't work: prints false
fmt.Println(t0.Before(max1))
// max1 < t0 doesn't work: prints true
fmt.Println(t0.After(max1))
fmt.Println(max1.Before(t0))
// t0 < max2 works: prints true
fmt.Println(t0.Before(max2))
// max2 < t0 works: prints false
fmt.Println(t0.After(max2))
fmt.Println(max2.Before(t0))
So while it is a bit of a pain you can use time.Unix(1<<63-62135596801, 999999999) if you want a max time.Time that is useful for comparisons like finding the minimum value in a range of times.
Time in go is stored as an int64 plus a 32bit Nanosec value (currently a uintptr for technical reasons), so there's no real worry about running out.
t := time.Unix(1<<63-1, 0)
fmt.Println(t.UTC())
prints 219250468-12-04 15:30:07 +0000 UTC
If for some reason you want a useful max time (see #cce's answer for details), you can use:
maxTime := time.Unix(1<<63-62135596801, 999999999)
Note that, although #cce's answer ensures After and Before will work, other APIs won't. UnixNano only works within ±292 years around 1970 (between 1678 and 2262). Also, since maximum duration is ~292 years, even those two will give a clamped result on Sub.
So, an alternative is to pick a minimum[1] value and do:
var MinTime = time.Unix(-2208988800, 0) // Jan 1, 1900
var MaxTime = MinTime.Add(1<<63 - 1)
Within these, everything should work.
[1]: An other obvious choice is time.Unix(0, 0) if you don't care about dates before 1970.