9 ms·
Time in Go
- neoyagami 11y agoGolang to me has the best time manipulation I ever seen, wannabe change the timezone, easy as eat pie, wanna add seconds? No prob, wanna compare dates? No biggie
- dvirsky 11y agoTrue, and for most cases the parsing is great too, but once you get off the beaten path of standard time formats, parsing times can be annoying.
- nulltype 11y agoDo you have any examples of annoying to parse time formats?
- paradite 11y agohttp://play.golang.org/p/hCoZ3tdeM_ http://play.golang.org/p/hCoZ3tdeM_ am I doing this correctly? Because it seems that golang does not recognize the abbreviations at all.
- deleted 11y ago[deleted]
- nulltype 11y agoIf you use time zones without offsets (just the name like PST instead of -0700) then you have to parse the time in a specific location http://play.golang.org/p/JzKAq09NtE http://play.golang.org/p/JzKAq09NtE I can only assume that the time zone name alone is insufficient to resolve ambiguous times.
- paradite 11y agoThen I think it is not very convenient to type out strings like "America/Los_Angeles" when you are dealing with timezones that come with abbreviations only. The whole point of using abbreviations is to avoid typing out the full name. Unless there is a way to get "America/Los_Angeles" from "PST"
- nulltype 11y agoYeah, I don't get why they require a location. On the other hand, -0700 isn't much longer than PST and parses directly.
- bitwalker 11y agoAbbreviations are reused in different locales. PST in one locale can have different rules than PST in another locale. The reason the fully qualified name is needed is because it uniquely identifies a locale for which timezone rules can be followed. Offsets aren't always the right thing to use either. If you are in America/Chicago and use -0600 for your timezone, that's only accurate during standard time, and is off by an hour for daylight savings time. Knowing how/when to shift offsets is part of the timezone rules associated with a locale, because they are not constant historically.
- nulltype 11y agoAh thanks, that confirms my theory of why the location is required to parse time zone names like PST. Offsets are probably going to be fine for recorded timestamps, if all you need is the absolute time that the timestamp represents. But yeah, timezones make things so complicated that there is no one true solution I guess.
- bitwalker 11y agoI mentioned this elsewhere in this thread, but abbreviations are not unique across timezones. The rules for timezones change based on locale, and if you have multiple zones with PST as an abbreviation, which one do you use? It has to be an explicit choice or it's almost certainly going to be wrong. There is no way to get America/Los_Angeles from PST without knowing the locale that the date and time is from.
- deleted 11y ago[deleted]
- dvirsky 11y agoI can find it later, but I just had this issue this week with timestamps sent from a browser, supposedly in RFC3339, but Go's RFC3339 format was not compliant with it. So naturally I made my own format template. Alas, the milliseconds part had arbitrary precision, which Go's parser doesn't like. So I had to revert to trying the timestamp with one, two ,three trailing digits, etc. Still, this is the only issue I have with the time library, and even that has only bothered me a couple of times in 3 years of work, so no biggie. Other than that it's indeed the best time library I've ever worked with.
- nulltype 11y agoI wasn't able to reproduce this issue, time.Parse(time.RFC3339Nano, "2015-09-10T06:31:39.442Z") seems to work correctly as long as the number of digits between "." and "Z" is 0-9
- dvirsky 11y agoThe problem is that the browser sends it in a different format (it's the HTML5 date-time input), 3399 simplified or something like that. So I ended up doing something like: > formats := []string{ string(time.RFC3339), "2006-01-02T15:04:05.0", "2006-01-02T15:04:05.00", "2006-01-02T15:04:05", "2006-01-02T15:04",} To make sure I have all cases covered
- rmetzler 11y agoI remember we had the same problem parsing time formats. Can't remember any specifics though (might have been timezone offsets), but I think parsing would be less error prone when there wouldn't be that magic date time formatting by example style used. I can totally understand that it is often easier to use, but compatibility with strftime is good for the experienced developer. There is a reason, why sites like [1] and several 3rd party libs [2] exist. [1]: http://fuckinggodateformat.com/ http://fuckinggodateformat.com/ [2]: https://github.com/search?q=language%3Ago+strftime&ref=searchresults&type=Repositories&utf8=%E2%9C%93 https://github.com/search?q=language%3Ago+strftime&ref=searc...
- skippednote 11y agoAgreed. Coming from JavaScript, I'm really happy with how intuitive it is to handle date and time with Go. I'm new to the language but I'm really happy with the simplicity and the design decisions made by the core team.
- mitchellh 11y agoMore languages should copy Go's time library. As someone who has written a lot of Go for years, I am always very quick to say that "time" is my favorite Go standard library. I love it. The "time" library is to Go what the "requests" [non-standard] library is to Python, in terms of a great API and simplicity. For some reason in every other language I've used (important, I don't know every time library! :P) the time library has always been adequate, but not much else. I think Python's "datetime" is a great example of a not great time library. At one point I was writing Python every day for a couple years. During that time, I could never ever remember the API for datetime, despite it being able to do what I needed to do well enough. I always had to open the docs. I think this is an example of an adequate library that just doesn't have a great API. Or, take the more generic problem of: I have a time, I have a duration, how do I tell if that duration has passed? Most developers I know (including myself) stumble on this for some period of time (see what I did there?), remembering what do I add to what and is it a greater than or a less than or do I subtract, etc. It is an easy problem, but always seems to require a little bit of thinking. Go's "time" library is nothing like this. Go's "time" library you will remember the API, it is intuitive. You can even guess it after writing Go for some period of time. It is that easy (ignoring the constants and non-standard printf-like function in it). Go's "time" comparison/arithmetic is incredible. Comparing times? Determining expiration? You'll almost never get this wrong the first time. (But write tests anyways) What I'm trying to say is: even if you don't like Go, take a look at how Go's "time" library works. I think it would be valuable for other languages. Other languages can probably even do it better (imagining better type systems around units), but I've never seen an API that feels as right for manipulating time as Go's time stdlib.
- ioddly 11y agoI think most language standard libraries just crib heavily off of the C interface, to their detriment. Using a preset date (the 2006-01-02) instead of format strings was really inspired; it took me about 10 minutes of staring at the documentation to understand how it worked, but it's a lot more readable once you get it.
- deleted 11y ago[deleted]
- paradite 11y agoSo I copied the example from http://golang.org/pkg/time/#Parse http://golang.org/pkg/time/#Parse and it did NOT work as expected: http://play.golang.org/p/Xd9oEeSffd http://play.golang.org/p/Xd9oEeSffd (timezone offset is zero)
- nulltype 11y agoThis works correctly if your locale includes the PST timezone (works fine on my computer). They should probably have a better example though.
- paradite 11y agoBy "works fine" you mean in your local environment or the go playground? Because it could potentially cause problems if the execution result varies from geographical locations and user's environment. I for one have no idea if my computer has a locale that includes PST timezone.
- nulltype 11y agoSorry I meant in my local environment. It's clear that the execution varies, as Parse(), unlike ParseInLocation() depends on the local environment, and play.golang.org probably uses some UTC locale.
- teraflop 11y agoThat seems to be an issue with the playground: https://github.com/golang/go/issues/12388 https://github.com/golang/go/issues/12388 It seems counter-intuitive to me that the behavior of time.Parse would depend on a "system location", but apparently it's by design.
- mratzloff 11y agoTime is location-dependant (time zones).
- 11y ago
- chmike 11y agoI'm surprised about the method to define a time format by example. There could be an ambiguity between month and day if the example is badly chosen. I prefer the C way with the struct and format. How do I get the time offset to UTC time at a given date and location ?
- tumdum_ 11y agoThere is no ambiguity - you are to provide predefined date in your layout. That predefined date (Mon Jan 2 15:04:05 -0700 MST 2006) is chosen in a way so that there is no ambiguity.
- chmike 11y agoThanks for the clarification. That info was missing in the date API presentation. Indeed, there is no ambiguity. Just two comments: 1. The date is not easy to remember 2. There is still an ambiguity with hours representation. What if I want to represent hours without a leading 0 for values smaller than 10 ? I guess I should than use my own formatting instead of predefined formating.
- redroom 11y ago> 1. The date is not easy to remember not easy to remember or just unfamiliar? > 2. There is still an ambiguity with hours representation. What if I want to represent hours without a leading 0 for values smaller than 10 ? is that not `3`? > I guess I should than use my own formatting instead of predefined formating. what do you mean? some common formats are defined here and how it all works is described there as well https://golang.org/pkg/time/#pkg-constants https://golang.org/pkg/time/#pkg-constants it also mentions https://golang.org/pkg/time/#Time.Format https://golang.org/pkg/time/#Time.Format (click the `> Example`)
- wallyhs 11y agoYou can remember it as 1 2 3 4 5 6 7: First month, second day, 3pm and four minutes and five seconds in the year '06, offset -7.
- 11y ago
- NKCSS 11y agoLooking at the docs it looks fine; only thing I can remark is that it's too bad that all sorts of constants are in the same namespace; I'd prefer to have all the formatting formats in a separate namespace for intance to make it more clear.
- jerf 11y agoThe problem with that is that Go has no support for a package that imports something from one package and re-exports it, so if you put things in two packages, you are in the general case requiring users to import two packages now. Another one of those things that makes sense to me at scale, as I've been bitten before in the dynamic languages by excessively complicated re-exporting systems, but locally is sometimes annoying.
- panic 11y agofmt.Printf("\n... and %v days after that ...\n", days) t2 := t1.Add(time.Duration(days) * time.Hour * 24) printTime(t2) How is that supposed to work with daylight saving time? Won't t2 end up one hour off from t1 if there is a daylight saving shift?
- nulltype 11y agoI find it easier to think of times in UTC rather than local timezones. In UTC (and in reality), those times will always be the same number of hours distance from each other. If you format it in different timezones (PDT and PST) then yeah, the formatted times will be at different hours of the day.
- heinrich5991 11y agoThat's not true for UTC, you'd need TAI for that. UTC includes leap seconds.
- p1mrx 11y agoIt's unfortunate that Go's time library cannot represent an infinite duration, or timestamps in the infinite past or infinite future. This makes it difficult to represent things like "this cache entry never expires", without relying on auxiliary data. Also, the minimum/maximum timestamp and overflow behavior seem to be poorly-defined.
- nulltype 11y agoYou could use the zero value (t.IsZero()) for that if you wanted to. That might be more confusing than a boolean flag though.
- p1mrx 11y agoIsZero works okay as an "infinite past" value, such as marking that a cache entry has already expired, but it's cumbersome to use as an "infinite future" because zero is naturally less than all the timestamps you're likely to encounter. It's also not a great idea to manually define the largest possible timestamp as a sentinel, because Add(Duration) doesn't check for overflow.
- colin_mccabe 11y agoYou can use nil to represent "no expiration."
- p1mrx 11y agoTime is a struct, so nil is not a legal value. You would have to store a pointer (var t *time.Time) instead.
- colin_mccabe 11y agoYes, I was suggesting storing a pointer to the entire structure.
- eru 11y agoIf only Go had better support for algebraic data structures..
- riobard 11y agoHas anybody ever wondered how Go's date formatting would work if the language is not English?
- JonnieCache 11y agoMy favorite is time.Ticker: It returns a channel of Time objects, dispensed at intervals of your choice. It even auto adjusts the interval based on how long your receiver takes to run.
- polskibus 11y agoSlightly offtopic but I always thought that Mike Bostock's bl.ocks.org was created to support D3 visualization sharing. This is the first time I see it used for another language, somewhat contrary to it's designed use.
- tel 11y agoTime libraries like this are a basket of inscrutable bugs waiting to happen. A simply API deceiving its users into thinking they're dealing with a simple subject. Time is anything but. There are a few notions of time, each wildly different from the other, which we as humans transparently conflate but which will throw computers into wild undecipherable loops: * Dates, specifically delimited by days, which are logical items of a calendar, not absolute points in time. They're never even points, for that matter, but explicit intervals. * Which calendar? In modern, western times you're okay with just one, but historical, international, and especially historical international dates you will fail. * Wall times or local times, e.g. what a human being might think the local time is. This is what we tend to mean when something ought to happen "at 3pm" but you should realize that there's no way to treat this uniformly: it holds on a particular day, in a particular location. Even simple ideas like "3pm will occur once a day" may not genuinely be true. * Universal times, of which there are a few variations each dealing with leap seconds differently, UTC, UT0/1/1R/2, TAI (https://en.wikipedia.org/wiki/Universal_Time https://en.wikipedia.org/wiki/Universal_Time) * Intervals of universal time, like "10 seconds" which are the only things which behave sanely from a physical point of view. This is why CPU time or Epoch time is nice. Adding two universal time intervals produces an interval twice as long. Adding a universal time interval to a universal time point produces a new universal time point which, subject to leap seconds, may or may not appear to be the proper number of seconds away. Adding a universal time interval to anything else is nonsense. * Intervals of wall-times like "half a day" which can be added meaningfully to combinations of wall-time and dates in a given calendar, useful for setting up human-interpretable re-occurrences. * Intervals of dates which can be added to dates within a calendar Other caveats apply, mostly having to do with the need to have an accurate geopolitical rundown of time disputes (the "Olson" database is probably sufficient) and a reasonably exact notion of where someone is in space that they are interpreting times (go look up Indiana's time zone and then throw away your standard US 4-tz notion). Generally, the idea is that when dealing with humans you want to think of time as being arranged into approximately 24-hour chunks (possibly longer or shorter and then overlapping or with weird gaps which should be smoothed out) assigned to each "day" of some assumed calendar. Then you can, given that person's exact point in space, convert points in this notion of time into a universal one using the Olson database. Converting intervals is harder and must be done by converting both ends and then subtracting in universal time, handling leap seconds if you care. The only time library I've ever used in anger which handles all of this is Haskell's `time` library. https://hackage.haskell.org/package/time http://two-wrongs.com/haskell-time-library-tutorial
- alblue 11y agoJava is an excellent example of how not to do date/time APIs (pre Java 8 anyway). My answer (from years ago): http://stackoverflow.com/a/1969651 http://stackoverflow.com/a/1969651
- MichaelGG 11y ago> time.Duration(mins) * time.Minute Seems a bit clunky. Why not time.FromMinutes(mins) or something to that effect? time.Duration is just "casting" an int64 to a Duration type?
- chrisbroadfoot 11y agoYes. That's why you usually write it like this: time.Now().Add(10 * time.Minute)