Skip to content
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

Closed
rsc opened this issue Mar 8, 2011 · 14 comments
Closed

package time changes #1594

rsc opened this issue Mar 8, 2011 · 14 comments

Comments

@rsc
Copy link
Contributor

rsc commented Mar 8, 2011

tracking issue for things that could be better about package time.
@rsc
Copy link
Contributor Author

rsc commented Mar 8, 2011

Comment 1:

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.

@dsymonds
Copy link
Contributor

dsymonds commented Mar 9, 2011

Comment 2:

Full timezone handling would be good, though perhaps that's better left to a separate
package.

@gopherbot
Copy link

Comment 3 by daveroundy:

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.

@alberts
Copy link
Contributor

alberts commented Mar 9, 2011

Comment 4:

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:

  1. time.tar.gz (6379 bytes)

@gopherbot
Copy link

Comment 5 by russel.winder:

ISO8601 does not appear to be a label for a valid date/time rendering.  RFC3339 is
similar but not the same.

@gopherbot
Copy link

Comment 6 by russel.winder:

The system currently works only with the Grgorian calendar.

@gopherbot
Copy link

Comment 7 by russel.winder:

ISO8601 allows for fractional seconds, none of the current renderings allow for this.

@gopherbot
Copy link

Comment 8 by russel.winder:

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

@mark-summerfield
Copy link

Comment 9:

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.

@gjemiller
Copy link

Comment 10:

Date math, and comparisons for a date-only type.  It's not good enough to use a
date-time type, because the equals test cannot easily ignore differences in the time
"fields".

@niemeyer
Copy link
Contributor

niemeyer commented Mar 9, 2011

Comment 11:

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.

@vdobler
Copy link
Contributor

vdobler commented Sep 8, 2011

Comment 12:

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.

@rsc
Copy link
Contributor Author

rsc commented Dec 9, 2011

Comment 13:

Labels changed: added priority-later.

@robpike
Copy link
Contributor

robpike commented Dec 12, 2011

Comment 14:

Status changed to Fixed.

@rsc rsc added fixed labels Dec 12, 2011
@rsc rsc self-assigned this Dec 12, 2011
@golang golang locked and limited conversation to collaborators Jun 24, 2016
@rsc rsc removed their assignment Jun 22, 2022
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

9 participants