New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
package time changes #1594
Labels
Comments
Might want to introduce types for use in other packages and in time. For example, the Atime field in FileInfo could have type time.Nanoseconds instead of being named Atime_ns. Might want to get rid of time.Time the struct and make the fields on-demand-computed methods of the time types instead. Status changed to Thinking. |
I think it'd be great to have code to deal with user-friendly date ranges, possibly in a separate package (e.g. time/range or maybe date/range?). Example of problems to be solved would be handling questions like "was this change made yesterday" or "was this change made in the last three weeks" or "was this change made last February". This sort of code tends to be tricky to write (e.g. is it yesterday in my time zone?), and a well-defined thoughtful API would be helpful. I'm not sure what this API would look like, but it's worth keeping in mind when one thinks about rewriting time. Examples of programs that use this kind of functionality would be git and darcs (and maybe hg?), but it can also show up on all sorts of web searching (e.g. a bank's transaction history display). It might also be handy to also have a function that translated a human-language string into a date string, but I'm not comfortable with English-specific functionality going into the core language. |
Here's some code we wrote to deal with time ranges (we called them intervals). Our first attempt did everything with seconds, but we've switched to using nanoseconds in most of our code, so there's a new interval type for that. One or both might be useful. The tests don't compile because they depend on another of our internal packages, but hopefully it gives some good API ideas. Attachments:
|
Adding to comment 3 above. Groovy has a category TimeCategory that creates an itnernal DSL that allows for expressions such as 1.day.ago, 24.hours.ago etc. cf. http://groovy.codehaus.org/api/groovy/time/TimeCategory.html |
At a high level it seems to me that it would be of great practical use if one could: (1) increment/decrement a "time" or "datetime" by human-friendly amounts, e.g., datetimeObject.Add(time.Weeks, 3), which would use the default (Gregorian) calendar so would account for leap years, leap seconds, etc. (2) measure the differences between two times, e.g., time.Compare(time.Days, datetime1, datetime2) int, again using the Gregorian calendar and accounting for leap years etc. and where the result is in the given units (so here, days). (3) conversion between time zones, e.g., datetimeObject.Zone(date.EST) datetimeObject which would return the same object if it is using EST or a new object using EST. Naturally there's lots more that could be done (see some of the Python third party time/date modules for example), but I think that 1 and 2 above would cover a lot of use cases. |
As an idea on one angle of the problem, Python's datetime+tzinfo support managed to enable timezone support while keeping the actual timezone implementation completely outside of the standard library, including competing implementations of how to define the timezones: http://docs.python.org/library/datetime.html The overall API is actually pretty small and was built as a redesign of the old raw time module, so it may be an interesting example to look at when pondering about what to do for Go. |
This is a lengthy comment but I think some more reasoning than just "that function would be cool" or "python does it right" would be appropriate; especially as calendar and clock stuff are obviously hard to do right (if you look at any other programming language) and Go is missing some needed functionality here. The following are my opinions based on excessive reading about date/time and a real world programming issue with date/time I tried to solve in Go. Below "current" state of Go referes to release.r.59 (but should be accurate for r60 too). 1) Go should not try to provide generic calendars: If someone needs a Maya or Egyptian calendar he should code his one. (Even Java ships only Gregorian, and the Java date/time API is bloated crop.) 2) Go should not try to deal with leap seconds. If you're doing radio astronomy you will know which "time" you are using and code your own. 3) So there is no need for date/time comparison: We're dealing with simple Newtonian (totally ordered) time so <, == and > on UTC seconds should be enough. (Implement your own spacetime for relativistic quantum mechanics if you need one.) 4) Comparing dates (ignoring time) is usefull _only_ if both are in the _same_ zone (e.g. local time) and than you just do lexical comparison on Year, Month, Day ignoring the other fields. Too simple for an API function. If you get string timestamps with different zones: Parse, convert to UTC, convert to local time and compare. This fails only in the unlikely case that your local daylight saving shift hits between both timestamps and put them wrongly into same/different day. This unlikely issues vanishes if a proper solution to 8a) below is available. 5) Some real problems can be solved perfectly fine with the current package time: - Absolute (Newtonian) time deltas can be done in UTC seconds - UTC seconds can be converted to local time (clock reading). 6) Package time should provide a function to determine the calendar week of a given timestamp. The ISO calendar week (not the US American one:-). The calendar week could even be incorporated into the Time struct itself. 7) Time does not provide sub-second resolution which makes it hard to use for stuff like process control or even logging. Wrapping Time in a struct with additional nanoseconds is easy, but this "workaround" won't be that easy any more once a solution (API) for number 8) below is found. 8) Some real life issues _cannot_ be handled properly with the current package time: a) There is no way to convert UTC seconds to some local time at an other location (than my servers location): E.g. my local time zone is Berlin, I have a time in UTC seconds and want its local time (clock reading) in Sydney (honouring daylight savings and that like). b) All issues regarding "shifted clock reading" in the sense of: "This time but in 3 days", "same date 20 years ago" or "same day in three month". These type of time manipulations cannot be translated to simple differences in absolute UTC time as such shifts might cross arbitrary daylight saving switches (and other). c) Question like "What's the start time (UTC) of this day (or week/month/...)" cannot be answered properly, again because start of this day (week/month/...) might have a different zoneoffset than the current time. IMHO: a) Is an inconvenience if you write an application for a server located in Zürich which must provide local clock readings of UTC time for Boston, Sydney and Moscow. No focus should be put on this until proper solution to b) is found. c) Most probably this issue could be answered quite easily if a good solution to b) is available. b) A solution to b) might provide enough packed intelligence to solve all these tiny question which bloat traditional date/time APIs. Any manipulation of absolute time can be done in UTC seconds. There is (currently) no way of manipulating "calendar readings" or "clock readings". While increasing/decreasing/comparing absolute times is i) easy and ii) never fails (ignoring int64 overflows) dealing with calendar/clock reading manipulations is neither easy nor always possible: Some manipulation requests are impossible to perform and will fail. Everything below deals with calendar/clock reading. Preliminary notes to understand the examples: In central Europe we switched to summer time (daylight saving) at "27.03.2011 02:00:00 CET" which means that one second later it was "27.03.2011 03:00:01 CEST". So there are no times like "27.03.2011 02:15:00 CET" and no clock readings from 02:00:00 to 02:59:59. February 29. occurs just once every four years (roughly) and there are no 30. of February and 31. of June (okay, you knew that). Very simple examples (those that could be handled properly by manipulating UTC seconds): "17.05.2011 15:30:00 CEST" + "3 days" == "20.05.2011 15:30:00 CEST" "17.05.2011 15:30:00 CEST" + "18 hours" == "19.05.2011 09:30:00 CEST" Not so simple examples (if doing in UTC seconds as months have different length, crossing February must take care of leap years) "17.05.2011 15:30:00 CEST" + "3 months" == "17.08.2011 15:30:00 CEST" "09.01.2011 15:30:00 CET" + "2 months" == "09.03.2011 15:30:00 CET" Examples which _cannot_ be handled by manipulating UTC seconds (as we switch zone offsets) "27.03.2011 01:30:00 CET" + "2 hours" == "27.03.2011 03:30:00 CEST" "27.03.2011 01:30:00 CET" + "2 days" == "29.03.2011 01:30:00 CEST" "15.02.2011 12:00:00 CET" + "3 months" == "15.05.2011 12:00:00 CEST" The +2hour case looks strange as the UTC time difference is only one hour. But it is consistent with the 2 days and the 3 months case. Examples which fail as the target calendar/clock reading does not exist: "27.03.2011 01:30:00 CET" + "1 hour" (neither 02:30:00 CET nor CEST) "31.03.2011 12:00:00 CETS" + "3 months" (no jun. 31. in any year) "29.02.2008 15:30:00 CET" + "1 year" (no feb. 29. in 2009) The failing cases could be made non-failing by rounding up or down to the next possible calendar/clock reading: "27.03.2011 01:30:00 CET" + "1 hour" -> 03:00:00 (up and down!) "31.03.2011 12:00:00 CETS" + "3 months" -> 30.6.2011 or 1.7.2011 "29.02.2008 15:30:00 CET" + "1 year" -> 29.2.2009 or 1.3.2011 The problem with the very simple expamples is: You do not now in advance that they are simple: The are simple (UTC-handable) only because the target time has the same zone offset So I would propose functions to manipulate calendar/clock readings of the following types: func ManipulateCCReading(t *Time, [delta]) (*Time, os.Err) func MustManipulateCCReading(t *Time, roundUp bool, [delta]) *Time "CC" is for CalendarAndOrClockReading". I would make it very clear in the name of those functions that they do not plain UTC second addition/subtraction. Obviously the names need to be discussed. How to specify the [delta] should be discussed. One "obvious" way is interface CCDelta { <whats needed>... } type HourDelta ... implementing CCDelta type DayDelta ... implementing CCDelta type MonthDelta ... implementing CCDelta type <XYZ>Delta ... implementing CCDelta func ManipulateCCReading(t *Time, deltas ...CCDelta) (*Time, os.Err) The possibly more Go idiomatic way would be type CCDelta struct {Hour, Day, Month, ... int} func ManipulateCCReading(t *Time, delta CCDelta) (*Time, os.Err) The implementation would be straight forward: Just some bookkeeping on leap years, month length, manipulation parsed fields in Time with carry. The tricky stuff lies in determining if the manipulation yields a new time with a different zone offset and correcting for the difference in the old and new zone offset. I admit I have not found a proper solution to the "zone offset of the target clock reading" problem. I asume (unprooved), that an iterative algorithm along (ignoring error cases) i) adjust reading, keep zone offset ii)convert to UTC, parse to local time iii) if zone offset changed: rerun from step i) would converge in 1 to 2 iterations. I could spend some time on this issue if there is some kind of consensus that package time need some improvements and which functions it should provide for which tasks. |
This issue was closed.
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
The text was updated successfully, but these errors were encountered: