* Support for sub-second time in decoded time @ 2019-07-29 9:48 Lars Ingebrigtsen 2019-07-29 14:03 ` Stefan Monnier ` (2 more replies) 0 siblings, 3 replies; 45+ messages in thread From: Lars Ingebrigtsen @ 2019-07-29 9:48 UTC (permalink / raw) To: emacs-devel Currently, encoded time has support for picoseconds. `decode-time' will throw away all sub-second time, which makes accurate round-tripping impossible. I mentioned this in a bug report, I think, but didn't get any response. I proposed to extend the list returned by `decode-time' (and accepted by `encode-time') to accommodate this -- I think this can be done in a backwards-compatible manner. `current-time' returns its data as (HIGH LOW USEC PSEC), but now that we have bignum support, perhaps we don't need to do it this way. What about just having a field in decoded times that's the fraction of a second? So 34.5603 seconds would be represented as (34 ... 5603) Opinions? -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Support for sub-second time in decoded time 2019-07-29 9:48 Support for sub-second time in decoded time Lars Ingebrigtsen @ 2019-07-29 14:03 ` Stefan Monnier 2019-07-29 14:12 ` Lars Ingebrigtsen 2019-07-29 14:23 ` Support for sub-second time in decoded time Eli Zaretskii 2019-07-29 16:46 ` Paul Eggert 2 siblings, 1 reply; 45+ messages in thread From: Stefan Monnier @ 2019-07-29 14:03 UTC (permalink / raw) To: Lars Ingebrigtsen; +Cc: emacs-devel > `current-time' returns its data as (HIGH LOW USEC PSEC), but now that we > have bignum support, perhaps we don't need to do it this way. What > about just having a field in decoded times that's the fraction of a > second? So 34.5603 seconds would be represented as > > (34 ... 5603) `encode-time` uses a fraction-representation (NOM . DENOM), which is probably easier to manipulate. [ Note: I find `encode-time` vs `decode-time` very confusing. ] Stefan ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Support for sub-second time in decoded time 2019-07-29 14:03 ` Stefan Monnier @ 2019-07-29 14:12 ` Lars Ingebrigtsen 2019-07-29 14:43 ` Stefan Monnier 2019-07-29 16:08 ` encode-time vs decode-time Stefan Monnier 0 siblings, 2 replies; 45+ messages in thread From: Lars Ingebrigtsen @ 2019-07-29 14:12 UTC (permalink / raw) To: Stefan Monnier; +Cc: emacs-devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> `current-time' returns its data as (HIGH LOW USEC PSEC), but now that we >> have bignum support, perhaps we don't need to do it this way. What >> about just having a field in decoded times that's the fraction of a >> second? So 34.5603 seconds would be represented as >> >> (34 ... 5603) > > `encode-time` uses a fraction-representation (NOM . DENOM), which is > probably easier to manipulate. You mean internally? It doesn't seem to be mentioned in the doc string, but it's an entire essay now... > [ Note: I find `encode-time` vs `decode-time` very confusing. ] I think the pair makes sense on the same level as {decode,encode}-coding-string does. That is, encoded time is what Emacs uses internally for most things, and decoded time is pretty close to what you er find in nature. Or at least it used to be; `endode-time' has gotten really complicated lately, and the doc string doesn't seem to be correct, ether, for some of the more odd things it apparently does. (let ((time (current-time))) (equal time (encode-time time))) => t (encode-time) -> Debugger entered--Lisp error: (wrong-number-of-arguments encode-time 0) But if we ignore all that, it's still conceptually sound. :-) --- encode-time is a built-in function in ‘src/timefns.c’. (encode-time &optional TIME FORM &rest OBSOLESCENT-ARGUMENTS) Probably introduced at or before Emacs version 19.29. This function does not change global state, including the match data. Convert optional TIME to a timestamp. Optional FORM specifies how the returned value should be encoded. This can act as the reverse operation of ‘decode-time’, which see. If TIME is a list (SECOND MINUTE HOUR DAY MONTH YEAR IGNORED DST ZONE) it is a decoded time in the style of ‘decode-time’, so that (encode-time (decode-time ...)) works. TIME can also be a time value. See ‘format-time-string’ for the various forms of a time value. For example, an omitted TIME stands for the current time. --- -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Support for sub-second time in decoded time 2019-07-29 14:12 ` Lars Ingebrigtsen @ 2019-07-29 14:43 ` Stefan Monnier 2019-07-29 15:00 ` Lars Ingebrigtsen 2019-07-29 16:08 ` encode-time vs decode-time Stefan Monnier 1 sibling, 1 reply; 45+ messages in thread From: Stefan Monnier @ 2019-07-29 14:43 UTC (permalink / raw) To: Lars Ingebrigtsen; +Cc: emacs-devel Lars Ingebrigtsen [2019-07-29 16:12:34] wrote: > Stefan Monnier <monnier@iro.umontreal.ca> writes: > >>> `current-time' returns its data as (HIGH LOW USEC PSEC), but now that we >>> have bignum support, perhaps we don't need to do it this way. What >>> about just having a field in decoded times that's the fraction of a >>> second? So 34.5603 seconds would be represented as >>> >>> (34 ... 5603) >> >> `encode-time` uses a fraction-representation (NOM . DENOM), which is >> probably easier to manipulate. > > You mean internally? No, as yet-another format. > It doesn't seem to be mentioned in the doc string, > but it's an entire essay now... It's here: If FORM is a positive integer, the time is returned as a pair of integers (TICKS . FORM), where TICKS is the number of clock ticks and FORM is the clock frequency in ticks per second. (Currently the positive integer should be at least 65536 if the returned value is expected to be given to standard functions expecting Lisp timestamps.) If FORM is t, the time is returned as (TICKS . PHZ), where PHZ is a platform dependent clock frequency in ticks per second. If FORM is ‘integer’, the time is -- Stefan ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Support for sub-second time in decoded time 2019-07-29 14:43 ` Stefan Monnier @ 2019-07-29 15:00 ` Lars Ingebrigtsen 2019-07-29 17:50 ` Stefan Monnier 0 siblings, 1 reply; 45+ messages in thread From: Lars Ingebrigtsen @ 2019-07-29 15:00 UTC (permalink / raw) To: Stefan Monnier; +Cc: emacs-devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >>> `encode-time` uses a fraction-representation (NOM . DENOM), which is >>> probably easier to manipulate. >> >> You mean internally? > > No, as yet-another format. > >> It doesn't seem to be mentioned in the doc string, >> but it's an entire essay now... > > It's here: > > If FORM is a positive integer, the time is returned as a pair of > integers (TICKS . FORM), where TICKS is the number of clock ticks and FORM > is the clock frequency in ticks per second. (Currently the positive > integer should be at least 65536 if the returned value is expected to > be given to standard functions expecting Lisp timestamps.) If FORM is > t, the time is returned as (TICKS . PHZ), where PHZ is a platform dependent > clock frequency in ticks per second. If FORM is ‘integer’, the time is Hm, OK. But I don't see how that relates to adding a new sub-second field to the output value from `decode-time'. :-) -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Support for sub-second time in decoded time 2019-07-29 15:00 ` Lars Ingebrigtsen @ 2019-07-29 17:50 ` Stefan Monnier 2019-07-30 11:33 ` Lars Ingebrigtsen 0 siblings, 1 reply; 45+ messages in thread From: Stefan Monnier @ 2019-07-29 17:50 UTC (permalink / raw) To: Lars Ingebrigtsen; +Cc: emacs-devel > Hm, OK. But I don't see how that relates to adding a new sub-second > field to the output value from `decode-time'. :-) I guess nothing, except to suggest to represent the resolution explicitly (i.e. to avoid the ambiguity of (34 ... 5603) which could be 34.5603 or 34.05603 ...). Stefan ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Support for sub-second time in decoded time 2019-07-29 17:50 ` Stefan Monnier @ 2019-07-30 11:33 ` Lars Ingebrigtsen 0 siblings, 0 replies; 45+ messages in thread From: Lars Ingebrigtsen @ 2019-07-30 11:33 UTC (permalink / raw) To: Stefan Monnier; +Cc: emacs-devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> Hm, OK. But I don't see how that relates to adding a new sub-second >> field to the output value from `decode-time'. :-) > > I guess nothing, except to suggest to represent the resolution > explicitly (i.e. to avoid the ambiguity of (34 ... 5603) which could > be 34.5603 or 34.05603 ...). Right. That makes more sense than "the bit that would come after the decimal point if this were floating point, which it isn't", which would be rather awkward to work with indeed. :-/ -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 45+ messages in thread
* encode-time vs decode-time 2019-07-29 14:12 ` Lars Ingebrigtsen 2019-07-29 14:43 ` Stefan Monnier @ 2019-07-29 16:08 ` Stefan Monnier 2019-07-30 10:32 ` Lars Ingebrigtsen 1 sibling, 1 reply; 45+ messages in thread From: Stefan Monnier @ 2019-07-29 16:08 UTC (permalink / raw) To: Lars Ingebrigtsen; +Cc: emacs-devel > I think the pair makes sense on the same level as > {decode,encode}-coding-string does. That is, encoded time is what Emacs > uses internally for most things, and decoded time is pretty close to > what you er find in nature. I think the problem is one of presentation and vocabulary, indeed. I think we should clarify: - "time string", as returned by format-time-string and accepted by parse-time-string. - "decoded time", i.e. a list of the form (SECOND MINUTE HOUR DAY MONTH YEAR IGNORED DST ZONE) I just pushed a patch which defines the `decoded-time` *type*, so we can refer to that precise name in docstrings. - "time counted in seconds" for which we support several representations: a plain number, a list of integers (HIGH LOW USEC PSEC), a pair of integers (NUMERATOR . DENOMINATOR). And part of the confusion for me is that `encode-time` not only encodes time, but can also be used to convert between different representations of "time counted in seconds" (in which case it's not the inverse of decode-time). Stefan ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-07-29 16:08 ` encode-time vs decode-time Stefan Monnier @ 2019-07-30 10:32 ` Lars Ingebrigtsen 2019-07-30 11:34 ` Andy Moreton 0 siblings, 1 reply; 45+ messages in thread From: Lars Ingebrigtsen @ 2019-07-30 10:32 UTC (permalink / raw) To: Stefan Monnier; +Cc: emacs-devel Stefan Monnier <monnier@iro.umontreal.ca> writes: > I think we should clarify: > > - "time string", as returned by format-time-string and accepted > by parse-time-string. > > - "decoded time", i.e. a list of the form (SECOND MINUTE HOUR DAY MONTH YEAR IGNORED DST ZONE) > I just pushed a patch which defines the `decoded-time` *type*, so we can > refer to that precise name in docstrings. Makes sense. > - "time counted in seconds" for which we support several representations: > a plain number, a list of integers (HIGH LOW USEC PSEC), a pair of > integers (NUMERATOR . DENOMINATOR). > > And part of the confusion for me is that `encode-time` not only encodes > time, but can also be used to convert between different representations > of "time counted in seconds" (in which case it's not the inverse of > decode-time). Yes, that's something that I think was added by Paul late last year, and which I think was a mistake, because it makes things conceptually confusing. I think the stuff to convert between the various "time counted in seconds" stuff should be a separate function, because it has nothing to do with "decoded time". -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-07-30 10:32 ` Lars Ingebrigtsen @ 2019-07-30 11:34 ` Andy Moreton 2019-07-30 11:37 ` Lars Ingebrigtsen 0 siblings, 1 reply; 45+ messages in thread From: Andy Moreton @ 2019-07-30 11:34 UTC (permalink / raw) To: emacs-devel On Tue 30 Jul 2019, Lars Ingebrigtsen wrote: > Stefan Monnier <monnier@iro.umontreal.ca> writes: > >> I think we should clarify: >> >> - "time string", as returned by format-time-string and accepted >> by parse-time-string. >> >> - "decoded time", i.e. a list of the form (SECOND MINUTE HOUR DAY MONTH YEAR IGNORED DST ZONE) >> I just pushed a patch which defines the `decoded-time` *type*, so we can >> refer to that precise name in docstrings. > > Makes sense. > >> - "time counted in seconds" for which we support several representations: >> a plain number, a list of integers (HIGH LOW USEC PSEC), a pair of >> integers (NUMERATOR . DENOMINATOR). >> >> And part of the confusion for me is that `encode-time` not only encodes >> time, but can also be used to convert between different representations >> of "time counted in seconds" (in which case it's not the inverse of >> decode-time). > > Yes, that's something that I think was added by Paul late last year, and > which I think was a mistake, because it makes things conceptually > confusing. > > I think the stuff to convert between the various "time counted in > seconds" stuff should be a separate function, because it has nothing to > do with "decoded time". It seems that the naming of these functions is unhelpful. They should clearly distinguish between timestamps (absolute time/date) and durations (relative intervals) and be named as such. AndyM ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-07-30 11:34 ` Andy Moreton @ 2019-07-30 11:37 ` Lars Ingebrigtsen 2019-07-30 17:54 ` Paul Eggert 0 siblings, 1 reply; 45+ messages in thread From: Lars Ingebrigtsen @ 2019-07-30 11:37 UTC (permalink / raw) To: Andy Moreton; +Cc: emacs-devel Andy Moreton <andrewjmoreton@gmail.com> writes: > It seems that the naming of these functions is unhelpful. They should > clearly distinguish between timestamps (absolute time/date) and > durations (relative intervals) and be named as such. Both encoded time and decoded time are what you call "absolute time/date"; just represented differently. (The "second" representation uses 1970 as the starting point.) In addition, a number of seconds can also be used as a duration, but that's a different matter. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-07-30 11:37 ` Lars Ingebrigtsen @ 2019-07-30 17:54 ` Paul Eggert 2019-07-30 22:50 ` Paul Eggert 2019-07-31 19:03 ` Lars Ingebrigtsen 0 siblings, 2 replies; 45+ messages in thread From: Paul Eggert @ 2019-07-30 17:54 UTC (permalink / raw) To: Lars Ingebrigtsen, Andy Moreton; +Cc: emacs-devel On 7/30/19 6:37 AM, Lars Ingebrigtsen wrote: > a number of seconds can also be used as a duration, but > that's a different matter. The issues are not that independent. Just as a Lisp timestamp like 1564500522 can be treated as absolute (2019-07-30 15:28:42 UTC) or relative (1564500522 seconds duration), a calendrical value like (42 28 15 30 7 2019 2 nil 0) can also be treated as an absolute time (the same absolute time, in this example) or as a relative time (using calendrical arithmetic). > adding an optional parameter to `decode-time' to also make it > include sub-second time in the decoded time structure it returns (also > as previously discussed) may be the right thing to do. However, I've > grepped through the sources now for usages of decoded time, and it kinda > looks to me like adding a ninth slot in decoded time structures would > probably not break anything. Any ninth slot should be a numerator-denominator pair if it's nonzero, to avoid losing precision. Something like this: (decode-time '(1564504076643563153 . 1000000000) t) => (56 27 16 30 7 2019 2 nil 0 (643563153 . 1000000000)) > this is very confusing indeed To some extent the confusion is inherent: there are a lot of useful ways to represent and manipulate times, and people unfamiliar with the issues will find this complexity confusing. That being said, it would be good to simplify the Emacs API for time without significantly hurting functionality or compatibility. So, how about this idea. First we go along the lines of your suggestion, and change decode-time to return a ninth slot with a numerator-denominator pair that preserves all the precision of its argument. Second, we change (encode-time TIME t) so that it also preserves all the precision of its argument. This will cause (encode-time (decode-time TIME) t) to return a value equivalent to TIME, which will simplify roundtripping. ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-07-30 17:54 ` Paul Eggert @ 2019-07-30 22:50 ` Paul Eggert 2019-07-31 19:03 ` Lars Ingebrigtsen 1 sibling, 0 replies; 45+ messages in thread From: Paul Eggert @ 2019-07-30 22:50 UTC (permalink / raw) To: Lars Ingebrigtsen, Andy Moreton; +Cc: emacs-devel On 7/30/19 12:54 PM, I wrote: > > So, how about this idea. First we go along the lines of your > suggestion, and change decode-time to return a ninth slot with a > numerator-denominator pair that preserves all the precision of its > argument. Second, we change (encode-time TIME t) so that it also > preserves all the precision of its argument. This will cause > (encode-time (decode-time TIME) t) to return a value equivalent to > TIME, which will simplify roundtripping. Come to think of it, we would also need to change this obsolescent API for encode-time: > As an obsolescent calling convention, if this function is called with > 6 or more arguments, the first 6 arguments are SECOND, MINUTE, HOUR, > DAY, MONTH, and YEAR, and specify the components of a decoded time, > where DST assumed to be -1 and FORM is omitted. If there are more > than 6 arguments the *last* argument is used as ZONE and any other > extra arguments are ignored, so that (apply #'encode-time > (decode-time ...)) works; otherwise ZONE is assumed to be nil. Several places in the code use this obsolete API and do (apply #'encode-time FOO) where FOO is either the munged result of an earlier decode-time or is created from scratch. So, if we made the change as described above, we'd also need to change the obsolescent API to be something like this: "As an obsolescent calling convention, if this function is called with 6 or more arguments, the first 6 arguments are SECOND, MINUTE, HOUR, DAY, MONTH, and YEAR, and specify the components of a decoded time, where DST assumed to be -1 and FORM is omitted. If there are between 7 and 9 arguments the *last* argument is used as ZONE and if there are 10 arguments the 9th is used as ZONE and the 10th as a fractional-second argument (TICKS . HZ) and in either case any other extra arguments are ignored, so that (apply #'encode-time (decode-time ...)) works. In this obsolete convention, the default ZONE is nil and the default fractional second is zero." Good thing that API is "obsolescent".... ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-07-30 17:54 ` Paul Eggert 2019-07-30 22:50 ` Paul Eggert @ 2019-07-31 19:03 ` Lars Ingebrigtsen 2019-07-31 19:31 ` Stefan Monnier 2019-08-06 1:48 ` Paul Eggert 1 sibling, 2 replies; 45+ messages in thread From: Lars Ingebrigtsen @ 2019-07-31 19:03 UTC (permalink / raw) To: Paul Eggert; +Cc: Andy Moreton, emacs-devel Paul Eggert <eggert@cs.ucla.edu> writes: >> this is very confusing indeed > To some extent the confusion is inherent: there are a lot of useful > ways to represent and manipulate times, and people unfamiliar with the > issues will find this complexity confusing. That being said, it would > be good to simplify the Emacs API for time without significantly > hurting functionality or compatibility. > > So, how about this idea. First we go along the lines of your > suggestion, and change decode-time to return a ninth slot with a > numerator-denominator pair that preserves all the precision of its > argument. Second, we change (encode-time TIME t) so that it also > preserves all the precision of its argument. This will cause > (encode-time (decode-time TIME) t) to return a value equivalent to > TIME, which will simplify roundtripping. I think this sounds workable, but I think it would be even better to introduce some new functions instead of overloading our poor encode-time function. When you did the major sanitation in this area last year (which was overall a very good thing), you did stuff like - (now (string-to-number (format-time-string "%s"))) + (now (encode-time nil 'integer)) and - (now (float-time)) + (now (encode-time nil 'integer)) and many similar transforms. The new code is definitely better than the old code, and it's not more cryptic than it used to be, really. However, I think it would have been even better to introduce a new function to enable people who are unfamiliar with how this all works to just read the code and understand what it's doing. So I think the things up above there should really be calls to a new function `get-current-time', that returns the same thing as `(encode-time nil 'integer)'. It should default to `integer', but can have an optional argument that says what form of "internal second time format" to return (i.e., `list', `t'). And then, finally, I think there should be a function to convert between these "internal second time" formats. Like... `convert-time-format', which would be like `(encode-time time 'list)' (etc). And then leave encode-time/decode-time a simple pair that would do nothing but convert between "internal second time format" and "decoded time format". -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-07-31 19:03 ` Lars Ingebrigtsen @ 2019-07-31 19:31 ` Stefan Monnier 2019-08-06 1:48 ` Paul Eggert 1 sibling, 0 replies; 45+ messages in thread From: Stefan Monnier @ 2019-07-31 19:31 UTC (permalink / raw) To: Lars Ingebrigtsen; +Cc: Paul Eggert, Andy Moreton, emacs-devel > So I think the things up above there should really be calls to a new > function `get-current-time', that returns the same thing as > `(encode-time nil 'integer)'. It should default to `integer', but can > have an optional argument that says what form of "internal second time > format" to return (i.e., `list', `t'). I tend to agree. Also I think we should try and standardize the representation of "internal second time" (presumably using the rational (NUM . DENOM) representation). So I think `get-current-time` should just always return this representation, and those who need another will just have to call `convert-time-format` explicitly. Stefan ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-07-31 19:03 ` Lars Ingebrigtsen 2019-07-31 19:31 ` Stefan Monnier @ 2019-08-06 1:48 ` Paul Eggert 2019-08-06 14:21 ` Eli Zaretskii 2019-08-07 11:41 ` Lars Ingebrigtsen 1 sibling, 2 replies; 45+ messages in thread From: Paul Eggert @ 2019-08-06 1:48 UTC (permalink / raw) To: Lars Ingebrigtsen; +Cc: Andy Moreton, emacs-devel Lars Ingebrigtsen wrote: > I think there should be a function to convert between > these "internal second time" formats. Like... `convert-time-format', > which would be like `(encode-time time 'list)' (etc). > > And then leave encode-time/decode-time a simple pair that would do > nothing but convert between "internal second time format" and "decoded > time format". OK, after some cogitation I installed something along those lines into master. I called the new function 'time-convert' by analogy with the existing functions time-add etc. So now, as you suggested, encode-time has reverted to its old role of converting from decoded timestamps to Lisp timestamps and its API is now simpler. I didn't follow your suggestion of adding another function that acts like current-time except it returns other Lisp timestamp formats, because (time-convert nil FORMAT) does that. I didn't follow Stefan's suggestion of adding another function that acts like current-time except it returns the (TICKS . HZ) format, because current-time is already planned do exactly that after the next release (when we will default CURRENT_TIME_LIST to false) and it'll be simpler if we have one function rather than two that do the same thing. ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-06 1:48 ` Paul Eggert @ 2019-08-06 14:21 ` Eli Zaretskii 2019-08-06 15:59 ` Paul Eggert 2019-08-07 11:41 ` Lars Ingebrigtsen 1 sibling, 1 reply; 45+ messages in thread From: Eli Zaretskii @ 2019-08-06 14:21 UTC (permalink / raw) To: Paul Eggert; +Cc: larsi, andrewjmoreton, emacs-devel > From: Paul Eggert <eggert@cs.ucla.edu> > Date: Mon, 5 Aug 2019 18:48:21 -0700 > Cc: Andy Moreton <andrewjmoreton@gmail.com>, emacs-devel@gnu.org > > OK, after some cogitation I installed something along those lines into master. I > called the new function 'time-convert' by analogy with the existing functions > time-add etc. So now, as you suggested, encode-time has reverted to its old role > of converting from decoded timestamps to Lisp timestamps and its API is now simpler. Thanks, but judging by the changes in Lisp files all over, it sounds like this is a backward-incompatible change? That'd be unfortunate. ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-06 14:21 ` Eli Zaretskii @ 2019-08-06 15:59 ` Paul Eggert 2019-08-06 18:23 ` Eli Zaretskii 0 siblings, 1 reply; 45+ messages in thread From: Paul Eggert @ 2019-08-06 15:59 UTC (permalink / raw) To: Eli Zaretskii; +Cc: larsi, andrewjmoreton, emacs-devel >> So now, as you suggested, encode-time has reverted to its old role >> of converting from decoded timestamps to Lisp timestamps and its API is now simpler. > > Thanks, but judging by the changes in Lisp files all over, it sounds > like this is a backward-incompatible change? It's not as scary as it might first appear. The changes to the lisp/* files that work around backward-incompatibility issues (by replacing (encode-time TIME FORM) with (time-convert TIME FORM)) are needed only to fix Emacs internals code that had already been changed to rely on Emacs 27 encode-time. Since Emacs 26 does not support (encode TIME FORM), users will not have to worry about making these kinds of changes to their own code. They only significant backward-compatibility issue I see is in the 2nd patch ("decode-time now returns subsec too"), which affects any user code that requires (= 9 (length (decode-time))). I originally proposed extending decode-time's API with a FORM option <https://lists.gnu.org/r/emacs-devel/2019-07/msg00750.html> that would cause decode-time to continue to behave as before unlless the given the new FORM argument; this would default to current behavior and so would avoid the backward-compatibility issue. However, Lars inspected uses of decode-time <https://lists.gnu.org/r/emacs-devel/2019-07/msg00772.html> and found that they invariably did something like (nth N (decode-time...)) or (apply #'encode-time 0 0 0 (nthcdr 3 (decode-time))). These uses will continue to work, so Lars convinced me that his proposal to return a 10-element list was better. If you prefer the more-backward-compatible approach I could look into redoing the time code that way, though I expect it'll be a bit more hassle to document it and to support it internally. ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-06 15:59 ` Paul Eggert @ 2019-08-06 18:23 ` Eli Zaretskii 2019-08-07 1:02 ` Paul Eggert 0 siblings, 1 reply; 45+ messages in thread From: Eli Zaretskii @ 2019-08-06 18:23 UTC (permalink / raw) To: Paul Eggert; +Cc: larsi, andrewjmoreton, emacs-devel > Cc: larsi@gnus.org, andrewjmoreton@gmail.com, emacs-devel@gnu.org > From: Paul Eggert <eggert@cs.ucla.edu> > Date: Tue, 6 Aug 2019 08:59:33 -0700 > > They only significant backward-compatibility issue I see is in the 2nd patch > ("decode-time now returns subsec too"), which affects any user code that > requires (= 9 (length (decode-time))). I originally proposed extending > decode-time's API with a FORM option > <https://lists.gnu.org/r/emacs-devel/2019-07/msg00750.html> that would cause > decode-time to continue to behave as before unlless the given the new FORM > argument; this would default to current behavior and so would avoid the > backward-compatibility issue. However, Lars inspected uses of decode-time > <https://lists.gnu.org/r/emacs-devel/2019-07/msg00772.html> and found that they > invariably did something like (nth N (decode-time...)) or (apply #'encode-time 0 > 0 0 (nthcdr 3 (decode-time))). Was this inspection done on Emacs' own code, or also outside Emacs? ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-06 18:23 ` Eli Zaretskii @ 2019-08-07 1:02 ` Paul Eggert 2019-08-07 2:41 ` Stefan Monnier ` (2 more replies) 0 siblings, 3 replies; 45+ messages in thread From: Paul Eggert @ 2019-08-07 1:02 UTC (permalink / raw) To: Eli Zaretskii; +Cc: larsi, andrewjmoreton, emacs-devel Eli Zaretskii wrote: > Was this inspection done on Emacs' own code, or also outside Emacs? Lars didn't say. I assume he meant Emacs's own code. Although almost all uses of decode-time will be unaffected by the change, there's little doubt that some user code somewhere will break because it (mistakenly) assumes that decode-time's result format will never be extended. If this is a real concern, we can go about the change in some other way. One alternative would be to leave decode-time's API unchanged from Emacs 26 and put the new functionality into a new function, say "time-calendrical". While we're at it, we could call the data structure that the new function returns a "calendrical timestamp" instead of a "decoded timestamp", and rename the recently-added functions make-decoded-time, decoded-time-hour, decoded-time-year etc. to make-calendrical-time, calendrical-hour, calendrical-year, etc. This would reduce confusion, as it is harder to remember what a "decoded time" is than to remember what a "calendrical time" is, at least for me. Also, we could document that the calendrical data structure may change in future versions, and that programs should use the new functions rather than inspect the raw data structure. Using the word "calendrical" in the new names would help avoid confusion with existing functions, which don't use that word in their names. ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-07 1:02 ` Paul Eggert @ 2019-08-07 2:41 ` Stefan Monnier 2019-08-07 14:47 ` Eli Zaretskii 2019-08-17 6:47 ` Paul Eggert 2019-08-07 11:33 ` Lars Ingebrigtsen 2019-08-07 14:44 ` Eli Zaretskii 2 siblings, 2 replies; 45+ messages in thread From: Stefan Monnier @ 2019-08-07 2:41 UTC (permalink / raw) To: Paul Eggert; +Cc: Eli Zaretskii, andrewjmoreton, larsi, emacs-devel > Although almost all uses of decode-time will be unaffected by the change, > there's little doubt that some user code somewhere will break because it > (mistakenly) assumes that decode-time's result format will never be > extended. If this is a real concern, we can go about the change in some > other way. Actually, while I agree that it's possible it will break something somewhere, it's rather unlikely. Stefan ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-07 2:41 ` Stefan Monnier @ 2019-08-07 14:47 ` Eli Zaretskii 2019-08-11 23:39 ` Lars Ingebrigtsen 2019-08-17 6:47 ` Paul Eggert 1 sibling, 1 reply; 45+ messages in thread From: Eli Zaretskii @ 2019-08-07 14:47 UTC (permalink / raw) To: Stefan Monnier; +Cc: larsi, eggert, andrewjmoreton, emacs-devel > From: Stefan Monnier <monnier@iro.umontreal.ca> > Cc: Eli Zaretskii <eliz@gnu.org>, larsi@gnus.org, andrewjmoreton@gmail.com, emacs-devel@gnu.org > Date: Tue, 06 Aug 2019 22:41:36 -0400 > > Actually, while I agree that it's possible it will break something > somewhere, it's rather unlikely. I think our record of making such predictions is rather poor. And anyway, suppose someone comes up with complaints about this change: what exactly do we say in response? The reason for the change is quite weak: it's basically an enhancement required by somewhat rare niche use cases. How can we justify breaking someone's code on such weak grounds? ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-07 14:47 ` Eli Zaretskii @ 2019-08-11 23:39 ` Lars Ingebrigtsen 0 siblings, 0 replies; 45+ messages in thread From: Lars Ingebrigtsen @ 2019-08-11 23:39 UTC (permalink / raw) To: Eli Zaretskii; +Cc: eggert, andrewjmoreton, Stefan Monnier, emacs-devel Eli Zaretskii <eliz@gnu.org> writes: >> Actually, while I agree that it's possible it will break something >> somewhere, it's rather unlikely. > > I think our record of making such predictions is rather poor. > > And anyway, suppose someone comes up with complaints about this > change: what exactly do we say in response? The reason for the change > is quite weak: it's basically an enhancement required by somewhat rare > niche use cases. How can we justify breaking someone's code on such > weak grounds? Having sub-second time resolution in calendar dates doesn't seem like a minor thing to me. I think if you say "now Emacs is ISO8601 compliant", then it's all the justification anybody could possibly need. I also think this is probably less likely to break anybody's code than when Emacs changed the output from `current-time' from being a list of two integers to four integers. The only possible real world problem I can see being slightly likely is somebody writing the output of `decode-time' to a file, and then reading it back in again. If the writer is a new Emacs, and the reader is an old Emacs (that calls `encode-time' on the data), then things will probably break. But I don't know of anybody doing stuff like that. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-07 2:41 ` Stefan Monnier 2019-08-07 14:47 ` Eli Zaretskii @ 2019-08-17 6:47 ` Paul Eggert 1 sibling, 0 replies; 45+ messages in thread From: Paul Eggert @ 2019-08-17 6:47 UTC (permalink / raw) To: Stefan Monnier; +Cc: Eli Zaretskii, andrewjmoreton, larsi, emacs-devel [-- Attachment #1: Type: text/plain, Size: 2425 bytes --] >> there's little doubt that some user code somewhere will break because it >> (mistakenly) assumes that decode-time's result format will never be >> extended. If this is a real concern, we can go about the change in some >> other way. > > Actually, while I agree that it's possible it will break something > somewhere, it's rather unlikely. Although I initially thought the same way (that's why I installed the patch that altered decode-time), I may have been a bit hasty. I searched for "decode-time" in all public GitHub source code files with an .el extension, and looked just in the first page of results (10 hits) and found one hit that would have a problem: https://github.com/tjim/nevermore/blob/5a3f29174b3a4b2b2e7a700a862f3b16a942687e/nm-dateparse.el It contains several instances of code like this: (defun nm-next-month (&optional dtime) "One month from now, or specified dtime" (pcase (or dtime (decode-time)) (`(,SECONDS ,MINUTES ,HOUR ,DAY ,MONTH ,YEAR ,DOW ,DST ,ZONE) (nm-noon (if (eq MONTH 12) `(,SECONDS ,MINUTES ,HOUR ,DAY ,1 ,(1+ YEAR) ,DOW ,DST ,ZONE) `(,SECONDS ,MINUTES ,HOUR ,DAY ,(1+ MONTH) ,YEAR ,DOW ,DST ,ZONE)))))) which won't work if decode-time returns a 10-element list. Although not a systematic study, this example suggests that we might want to be cautious about changing decode-time to return a 10-element list. With that in mind, I installed the attached patch, which causes decode-time to behave at it does in Emacs 26 unless you pass it a new optional argument. And even with the new argument, it still returns a 9-element list so the above code will still work. Eli Zaretskii wrote: > Another alternative is to make the SECONDS member be a float, then we > could return the extra precision there. Floats suffer from rounding confusion, and won't suffice for attosecond-precision timestamps - admittedly not something one runs into every day, but they are needed for some physics applications. The experience that I've had with floating-point timestamps over the years has been negative, for the usual reasons. So the patch I installed uses the (TICKS . HZ) form that can handle attoseconds - indeed, it can even handle zeptoseconds, which were first needed by experimental physicists in 2016, according to Jason Daley <https://www.smithsonianmag.com/smart-news/physicists-record-smallest-slice-time-yet-180961085/>. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-More-compatible-subsecond-calendrical-timestamps.patch --] [-- Type: text/x-patch; name="0001-More-compatible-subsecond-calendrical-timestamps.patch", Size: 60524 bytes --] From 37257d6acadff17bd1e52cfa460950bcb684c5c3 Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> Date: Fri, 16 Aug 2019 22:09:04 -0700 Subject: [PATCH] More-compatible subsecond calendrical timestamps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of appending a subseconds member to the result of ‘decode-time’, this keeps the format unchanged unless you give a new optional argument to ‘decode-time’. Also, the augmented format now puts the subsecond info in the SECONDS element, so the total number of elements is unchanged; this is more compatible with code that expects the traditional 9 elements, such as ‘(pcase decoded-time (`(,SEC ,MIN ,HOUR ,DAY ,MON ,YEAR ,DOW ,DST ,ZONE) ...) ...)’. * doc/lispref/os.texi, doc/misc/emacs-mime.texi, etc/NEWS: * lisp/net/soap-client.el (soap-decode-date-time): * lisp/simple.el (decoded-time): Document the new behavior. * lisp/calendar/icalendar.el (icalendar--decode-isodatetime): * lisp/calendar/iso8601.el (iso8601-parse) (iso8601-parse-time, iso8601-parse-duration) (iso8601--decoded-time): * lisp/calendar/parse-time.el (parse-time-string): * lisp/calendar/time-date.el (decoded-time-add) (decoded-time--alter-second): * lisp/org/org.el (org-parse-time-string): * lisp/simple.el (decoded-time): * src/timefns.c (Fdecode_time, Fencode_time): * test/lisp/calendar/icalendar-tests.el: (icalendar--decode-isodatetime): * test/lisp/calendar/iso8601-tests.el (test-iso8601-date-years) (test-iso8601-date-dates, test-iso8601-date-obsolete) (test-iso8601-date-weeks, test-iso8601-date-ordinals) (test-iso8601-time, test-iso8601-combined) (test-iso8601-duration, test-iso8601-intervals) (standard-test-dates, standard-test-time-of-day-fractions) (standard-test-time-of-day-beginning-of-day) (standard-test-time-of-day-utc) (standard-test-time-of-day-zone) (standard-test-date-and-time-of-day, standard-test-interval): * test/lisp/calendar/parse-time-tests.el (parse-time-tests): * test/src/timefns-tests.el (format-time-string-with-zone) (encode-time-dst-numeric-zone): Revert recent changes that added a SUBSECS member to calendrical timestamps, since that component is no longer present (the info, if any, is now in the SECONDS member). * lisp/calendar/time-date.el (decoded-time-add) (decoded-time--alter-second): Support fractional seconds in the new form. Simplify. * src/timefns.c (Fdecode_time): Support new arg FORM. (Fencode_time): Support subsecond resolution. * test/src/timefns-tests.el (format-time-string-with-zone) (decode-then-encode-time): Test subsecond calendrical timestamps. --- doc/lispref/os.texi | 65 +++++---- doc/misc/emacs-mime.texi | 2 +- etc/NEWS | 22 ++- lisp/calendar/icalendar.el | 2 +- lisp/calendar/iso8601.el | 14 +- lisp/calendar/parse-time.el | 8 +- lisp/calendar/time-date.el | 75 ++++------ lisp/net/soap-client.el | 4 +- lisp/org/org.el | 4 +- lisp/simple.el | 8 +- src/timefns.c | 178 +++++++++++++---------- test/lisp/calendar/icalendar-tests.el | 8 +- test/lisp/calendar/iso8601-tests.el | 190 ++++++++++++------------- test/lisp/calendar/parse-time-tests.el | 18 +-- test/src/timefns-tests.el | 46 +++--- 15 files changed, 337 insertions(+), 307 deletions(-) diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi index 70ae39e6ab..49c07380c5 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi @@ -1478,23 +1478,23 @@ Time Conversion @end example @end defun -@defun decode-time &optional time zone +@defun decode-time &optional time zone form This function converts a time value into calendrical information. If you don't specify @var{time}, it decodes the current time, and similarly @var{zone} defaults to the current time zone rule. @xref{Time Zone Rules}. -The return value is a list of ten elements, as follows: +The @var{form} argument controls the form of the returned +@var{seconds} element, as described below. +The return value is a list of nine elements, as follows: @example -(@var{seconds} @var{minutes} @var{hour} @var{day} @var{month} @var{year} - @var{dow} @var{dst} @var{utcoff} @var{subsec}) +(@var{seconds} @var{minutes} @var{hour} @var{day} @var{month} @var{year} @var{dow} @var{dst} @var{utcoff}) @end example Here is what the elements mean: @table @var @item seconds -The number of seconds past the minute, as an integer between 0 and 59. -On some operating systems, this is 60 for leap seconds. +The number of seconds past the minute, with form described below. @item minutes The number of minutes past the hour, as an integer between 0 and 59. @item hour @@ -1514,22 +1514,33 @@ Time Conversion @item utcoff An integer indicating the Universal Time offset in seconds, i.e., the number of seconds east of Greenwich. -@item subsec -The number of subseconds past the second, as either 0 or a Lisp -timestamp @code{(@var{ticks} . @var{hz})} representing a nonnegative -fraction less than 1. @end table +The @var{seconds} element is a Lisp timestamp that is nonnegative and +less than 61; it is less than 60 except during positive leap seconds +(assuming the operating system supports leap seconds). If the +optional @var{form} argument is @code{t}, @var{seconds} uses the same +precision as @var{time}; if @var{form} is @code{integer}, +@var{seconds} is truncated to an integer. For example, if @var{time} +is the timestamp @code{(1566009571321 . 1000)}, which represents +2019-08-17 02:39:31.321 UTC on typical systems that lack leap seconds, +then @code{(decode-time @var{time} t t)} returns @code{((31321 . 1000) +39 2 17 8 2019 6 nil 0)}, whereas @code{(decode-time @var{time} t +'integer)} returns @code{(31 39 2 17 8 2019 6 nil 0)}. If @var{form} +is omitted or @code{nil}, it currently defaults to @code{integer} but +this default may change in future Emacs releases, so callers requiring +a particular form should specify @var{form}. + @strong{Common Lisp Note:} Common Lisp has different meanings for -@var{dow} and @var{utcoff}, and lacks @var{subsec}. +@var{dow} and @var{utcoff}, and its @var{second} is an integer between +0 and 59 inclusive. To access (or alter) the elements in the time value, the @code{decoded-time-second}, @code{decoded-time-minute}, @code{decoded-time-hour}, @code{decoded-time-day}, @code{decoded-time-month}, @code{decoded-time-year}, -@code{decoded-time-weekday}, @code{decoded-time-dst}, -@code{decoded-time-zone} and @code{decoded-time-subsec} -accessors can be used. +@code{decoded-time-weekday}, @code{decoded-time-dst} and +@code{decoded-time-zone} accessors can be used. For instance, to increase the year in a decoded time, you could say: @@ -1551,7 +1562,7 @@ Time Conversion could say: @lisp -(let ((time (decode-time)) +(let ((time (decode-time nil nil t)) (delta (make-decoded-time :month 2))) (encode-time (decoded-time-add time delta))) @end lisp @@ -1585,22 +1596,21 @@ Time Conversion Ordinarily the first argument is a list @code{(@var{second} @var{minute} @var{hour} @var{day} @var{month} -@var{year} @var{ignored} @var{dst} @var{zone} @var{subsec})} that specifies a +@var{year} @var{ignored} @var{dst} @var{zone})} that specifies a decoded time in the style of @code{decode-time}, so that @code{(encode-time (decode-time ...))} works. For the meanings of these list members, see the table under @code{decode-time}. As an obsolescent calling convention, this function can be given six -through ten arguments. The first six arguments @var{second}, +or more arguments. The first six arguments @var{second}, @var{minute}, @var{hour}, @var{day}, @var{month}, and @var{year} -specify most of the components of a decoded time. If there are seven -through nine arguments the @emph{last} argument is used as @var{zone}, -and if there are ten arguments the ninth specifies @var{zone} and the -tenth specifies @var{subsec}; in either case any other extra arguments -are ignored, so that @code{(apply #'encode-time (decode-time ...))} -works. In this obsolescent convention, @var{zone} defaults to the -current time zone rule (@pxref{Time Zone Rules}), @var{subsec} -defaults to 0, and @var{dst} is treated as if it was @minus{}1. +specify most of the components of a decoded time. If there are more +than six arguments the @emph{last} argument is used as @var{zone} and +any other extra arguments are ignored, so that @code{(apply +#'encode-time (decode-time ...))} works. In this obsolescent +convention, @var{zone} defaults to the current time zone rule +(@pxref{Time Zone Rules}), and @var{dst} is treated as if it was +@minus{}1. Year numbers less than 100 are not treated specially. If you want them to stand for years above 1900, or years above 2000, you must alter them @@ -1615,9 +1625,8 @@ Time Conversion @end example You can perform simple date arithmetic by using out-of-range values for -@var{seconds}, @var{minutes}, @var{hour}, @var{day}, @var{month}, and -@var{subsec}; for example, day 0 means the day preceding the given -month. +@var{seconds}, @var{minutes}, @var{hour}, @var{day}, and @var{month}; +for example, day 0 means the day preceding the given month. The operating system puts limits on the range of possible time values; if the limits are exceeded while encoding the time, an error results. diff --git a/doc/misc/emacs-mime.texi b/doc/misc/emacs-mime.texi index c411bf3d68..eb829b0612 100644 --- a/doc/misc/emacs-mime.texi +++ b/doc/misc/emacs-mime.texi @@ -1535,7 +1535,7 @@ time-date @example (parse-time-string "Sat Sep 12 12:21:54 1998 +0200") -@result{} (54 21 12 12 9 1998 6 -1 7200 0) +@result{} (54 21 12 12 9 1998 6 -1 7200) (time-convert (date-to-time "Sat Sep 12 12:21:54 1998 +0200") diff --git a/etc/NEWS b/etc/NEWS index edce7b3e57..53408a871e 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2116,10 +2116,20 @@ probing the innards of a timestamp directly, or creating a timestamp by hand. +++ -*** Decoded (calendrical) timestamps now have a new subsecond member. -This affects functions like decode-time and parse-time-string that -generate these timestamps, and functions like encode-time that accept -them. +*** Decoded (calendrical) timestamps now have subsecond resolution. +This affects decode-time, which generates these timestamps, as well as +functions like encode-time that accept them. The subsecond info is +present as a (TICKS . HZ) value in the seconds element of a decoded +timestamp, and decode-time has a new optional FORM argument specifying +the form of the seconds member. For example, if X is the timestamp +(1566009571321878186 . 1000000000), which represents 2019-08-17 +02:39:31.321878186 UTC, (decode-time X t t) returns ((31321878186 +. 1000000000) 39 2 17 8 2019 6 nil 0) instead of the traditional (31 +39 2 17 8 2019 6 nil 0) returned by plain (decode-time X t). Although +the default FORM is currently 'integer', which truncates the seconds +to an integer and is the traditional behavior, this default may change +in future Emacs versions, so callers requiring an integer should +specify FORM explicitly. +++ *** 'encode-time' supports a new API '(encode-time TIME)'. @@ -2152,8 +2162,8 @@ with POSIX.1-2017. *** To access (or alter) the elements a decoded time value, the 'decoded-time-second', 'decoded-time-minute', 'decoded-time-hour', 'decoded-time-day', 'decoded-time-month', 'decoded-time-year', -'decoded-time-weekday', 'decoded-time-dst', 'decoded-time-zone', -and 'decoded-time-subsec' accessors can be used. +'decoded-time-weekday', 'decoded-time-dst' and 'decoded-time-zone' +accessors can be used. *** The new functions 'date-days-in-month' (which will say how many days there are in a month in a specific year), 'date-ordinal-to-time' diff --git a/lisp/calendar/icalendar.el b/lisp/calendar/icalendar.el index 84f579ad44..c2688705e3 100644 --- a/lisp/calendar/icalendar.el +++ b/lisp/calendar/icalendar.el @@ -644,7 +644,7 @@ icalendar--decode-isodatetime ;; create the decoded date-time ;; FIXME!?! (let ((decoded-time (list second minute hour day month year - nil -1 zone 0))) + nil -1 zone))) (condition-case nil (decode-time (encode-time decoded-time)) (error diff --git a/lisp/calendar/iso8601.el b/lisp/calendar/iso8601.el index 51f5dff909..30352c7e75 100644 --- a/lisp/calendar/iso8601.el +++ b/lisp/calendar/iso8601.el @@ -129,8 +129,7 @@ iso8601-parse (let ((time (iso8601-parse-time time-string))) (setf (decoded-time-hour date) (decoded-time-hour time)) (setf (decoded-time-minute date) (decoded-time-minute time)) - (setf (decoded-time-second date) (decoded-time-second time)) - (setf (decoded-time-subsec date) (decoded-time-subsec time)))) + (setf (decoded-time-second date) (decoded-time-second time)))) ;; The time zone is optional. (when zone-string (setf (decoded-time-zone date) @@ -237,8 +236,6 @@ iso8601-parse-time (iso8601--decoded-time :hour hour :minute (or minute 0) :second (or second 0) - ;; FIXME: Support subsec. - :subsec 0 :zone (and zone (* 60 (iso8601-parse-zone zone))))))))) @@ -277,9 +274,7 @@ iso8601-parse-duration :day (or (match-string 3 string) 0) :hour (or (match-string 5 string) 0) :minute (or (match-string 6 string) 0) - :second (or (match-string 7 string) 0) - ;; FIXME: Support subsec. - :subsec 0)) + :second (or (match-string 7 string) 0))) ;; PnW: Weeks. ((iso8601--match iso8601--duration-week-match string) (let ((weeks (string-to-number (match-string 1 string)))) @@ -341,7 +336,7 @@ iso8601--value (cl-defun iso8601--decoded-time (&key second minute hour day month year - dst zone subsec) + dst zone) (list (iso8601--value second) (iso8601--value minute) (iso8601--value hour) @@ -350,8 +345,7 @@ iso8601--value (iso8601--value year) nil dst - zone - subsec)) + zone)) (defun iso8601--encode-time (time) "Like `encode-time', but fill in nil values in TIME." diff --git a/lisp/calendar/parse-time.el b/lisp/calendar/parse-time.el index 9af93b5b1e..b0b277db77 100644 --- a/lisp/calendar/parse-time.el +++ b/lisp/calendar/parse-time.el @@ -148,7 +148,7 @@ parse-time-rules ;;;###autoload (defun parse-time-string (string) - "Parse the time in STRING into (SEC MIN HOUR DAY MON YEAR DOW DST TZ SUBSEC). + "Parse the time in STRING into (SEC MIN HOUR DAY MON YEAR DOW DST TZ). STRING should be something resembling an RFC 822 (or later) date-time, e.g., \"Fri, 25 Mar 2016 16:24:56 +0100\", but this function is somewhat liberal in what format it accepts, and will attempt to @@ -156,7 +156,7 @@ parse-time-string The values returned are identical to those of `decode-time', but any unknown values other than DST are returned as nil, and an unknown DST value is returned as -1." - (let ((time (list nil nil nil nil nil nil nil -1 nil nil)) + (let ((time (list nil nil nil nil nil nil nil -1 nil)) (temp (parse-time-tokenize (downcase string)))) (while temp (let ((parse-time-elt (pop temp)) @@ -193,10 +193,6 @@ parse-time-string (funcall this))) parse-time-val))) (setf (nth (pop slots) time) new-val)))))))) - ;; FIXME: Currently parse-time-string does not parse subseconds. - ;; So if seconds were found, set subseconds to zero. - (when (nth 0 time) - (setf (nth 9 time) 0)) time)) (defun parse-iso8601-time-string (date-string) diff --git a/lisp/calendar/time-date.el b/lisp/calendar/time-date.el index fa5e886869..f3d252f03c 100644 --- a/lisp/calendar/time-date.el +++ b/lisp/calendar/time-date.el @@ -420,26 +420,13 @@ decoded-time-add ;; Do the time part, which is pretty simple (except for leap ;; seconds, I guess). - (setq seconds (+ (* (or (decoded-time-hour delta) 0) 3600) - (* (or (decoded-time-minute delta) 0) 60) - (or (decoded-time-second delta) 0))) - (when (decoded-time-subsec delta) - (let* ((subsec (time-convert (time-add (decoded-time-subsec time) - (decoded-time-subsec delta)) - t)) - (s (time-convert subsec 'integer))) - (setq seconds (+ seconds s)) - (setf (decoded-time-subsec time) (time-subtract subsec s)))) - ;; Time zone adjustments are basically the same as time adjustments. - (setq seconds (+ seconds (or (decoded-time-zone delta) 0))) - - (cond - ((> seconds 0) - (decoded-time--alter-second time seconds t)) - ((< seconds 0) - (decoded-time--alter-second time (abs seconds) nil))) + (setq seconds (time-add (+ (* (or (decoded-time-hour delta) 0) 3600) + (* (or (decoded-time-minute delta) 0) 60) + (or (decoded-time-zone delta) 0)) + (or (decoded-time-second delta) 0))) + (decoded-time--alter-second time seconds) time)) (defun decoded-time--alter-month (time increase) @@ -472,38 +459,31 @@ decoded-time--alter-day (date-days-in-month (decoded-time-year time) (decoded-time-month time)))))) -(defun decoded-time--alter-second (time seconds increase) - "Increase or decrease the time in TIME by SECONDS." - (let ((old (+ (* (or (decoded-time-hour time) 0) 3600) - (* (or (decoded-time-minute time) 0) 60) - (or (decoded-time-second time) 0)))) - - (if increase - (progn - (setq old (+ old seconds)) - (setf (decoded-time-second time) (% old 60) - (decoded-time-minute time) (% (/ old 60) 60) - (decoded-time-hour time) (% (/ old 3600) 24)) - ;; Hm... DST... - (let ((days (/ old (* 60 60 24)))) - (while (> days 0) - (decoded-time--alter-day time t) - (cl-decf days)))) - (setq old (abs (- old seconds))) - (setf (decoded-time-second time) (% old 60) - (decoded-time-minute time) (% (/ old 60) 60) - (decoded-time-hour time) (% (/ old 3600) 24)) - ;; Hm... DST... - (let ((days (/ old (* 60 60 24)))) - (while (> days 0) - (decoded-time--alter-day time nil) - (cl-decf days)))))) +(defun decoded-time--alter-second (time seconds) + "Increase the time in TIME by SECONDS." + (let* ((secsperday 86400) + (old (time-add (+ (* 3600 (or (decoded-time-hour time) 0)) + (* 60 (or (decoded-time-minute time) 0))) + (or (decoded-time-second time) 0))) + (new (time-add old seconds))) + ;; Hm... DST... + (while (time-less-p new 0) + (decoded-time--alter-day time nil) + (setq new (time-add new secsperday))) + (while (not (time-less-p new secsperday)) + (decoded-time--alter-day time t) + (setq new (time-subtract new secsperday))) + (let ((sec (time-convert new 'integer))) + (setf (decoded-time-second time) (time-add (% sec 60) + (time-subtract new sec)) + (decoded-time-minute time) (% (/ sec 60) 60) + (decoded-time-hour time) (/ sec 3600))))) (cl-defun make-decoded-time (&key second minute hour day month year - dst zone subsec) + dst zone) "Return a `decoded-time' structure with only the keywords given filled out." - (list second minute hour day month year nil dst zone subsec)) + (list second minute hour day month year nil dst zone)) (defun decoded-time-set-defaults (time &optional default-zone) "Set any nil values in `decoded-time' TIME to default values. @@ -533,9 +513,6 @@ decoded-time-set-defaults (when (and (not (decoded-time-zone time)) default-zone) (setf (decoded-time-zone time) 0)) - - (unless (decoded-time-subsec time) - (setf (decoded-time-subsec time) 0)) time) (provide 'time-date) diff --git a/lisp/net/soap-client.el b/lisp/net/soap-client.el index eb08511171..7ce7d79c74 100644 --- a/lisp/net/soap-client.el +++ b/lisp/net/soap-client.el @@ -561,8 +561,8 @@ soap-decode-date-time Return a list in a format (SEC MINUTE HOUR DAY MONTH YEAR SEC-FRACTION DATATYPE ZONE). This format is meant to be similar to that returned by `decode-time' (and compatible with -`encode-time'). The differences are the SUBSEC (fractional -seconds) field is omitted, the DOW (day-of-week) field +`encode-time'). The differences are the SEC (seconds) +field is always an integer, the DOW (day-of-week) field is replaced with SEC-FRACTION, a float representing the fractional seconds, and the DST (daylight savings time) field is replaced with DATATYPE, a symbol representing the XSD primitive diff --git a/lisp/org/org.el b/lisp/org/org.el index 336c413c8c..ab29353ae8 100644 --- a/lisp/org/org.el +++ b/lisp/org/org.el @@ -17775,12 +17775,14 @@ org-parse-time-string (string-to-number (match-string 4 s)) (string-to-number (match-string 3 s)) (string-to-number (match-string 2 s)) - nil nil nil 0)) + nil nil nil)) ((string-match "^<[^>]+>$" s) ;; FIXME: `decode-time' needs to be called with ZONE as its ;; second argument. However, this requires at least Emacs ;; 25.1. We can do it when we switch to this version as our ;; minimal requirement. + ;; FIXME: decode-time needs to be called with t as its + ;; third argument, but this requires at least Emacs 27. (decode-time (org-matcher-time s))) (t (error "Not a standard Org time string: %s" s)))) diff --git a/lisp/simple.el b/lisp/simple.el index cb938bb341..fdf7d893cd 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -9082,8 +9082,9 @@ capitalize-dwim (:copier nil) (:type list)) (second nil :documentation "\ -This is an integer between 0 and 60 (inclusive). (60 is a leap -second, which only some operating systems support.)") +This is an integer or a Lisp timestamp (TICKS . HZ) representing a nonnegative +number of seconds less than 61. (If not less than 60, it is a leap second, +which only some operating systems support.)") (minute nil :documentation "This is an integer between 0 and 59 (inclusive).") (hour nil :documentation "This is an integer between 0 and 23 (inclusive).") (day nil :documentation "This is an integer between 1 and 31 (inclusive).") @@ -9099,9 +9100,6 @@ capitalize-dwim (zone nil :documentation "\ This is an integer indicating the UTC offset in seconds, i.e., the number of seconds east of Greenwich.") - (subsec nil :documentation "\ -This is 0, or is an integer pair (TICKS . HZ) indicating TICKS/HZ seconds, -where HZ is positive and TICKS is nonnegative and less than HZ.") ) \f diff --git a/src/timefns.c b/src/timefns.c index 979550c843..16c39c8349 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -1374,8 +1374,8 @@ usage: (format-time-string FORMAT-STRING &optional TIME ZONE) */) t, zone, &tm); } -DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 2, 0, - doc: /* Decode a time value as (SEC MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF SUBSEC). +DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 3, 0, + doc: /* Decode a time value as (SEC MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF). The optional TIME is the time value to convert. See `format-time-string' for the various forms of a time value. @@ -1385,29 +1385,33 @@ the TZ environment variable. It can also be a list (as from `current-time-zone') or an integer (the UTC offset in seconds) applied without consideration for daylight saving time. +The optional FORM specifies the form of the SEC member. If `integer', +SEC is an integer; if t, SEC uses the same resolution as TIME. An +omitted or nil FORM is currently treated like `integer', but this may +change in future Emacs versions. + To access (or alter) the elements in the time value, the `decoded-time-second', `decoded-time-minute', `decoded-time-hour', `decoded-time-day', `decoded-time-month', `decoded-time-year', -`decoded-time-weekday', `decoded-time-dst', `decoded-time-zone' and -`decoded-time-subsec' accessors can be used. +`decoded-time-weekday', `decoded-time-dst' and `decoded-time-zone' +accessors can be used. -The list has the following ten members: SEC is an integer between 0 -and 60; SEC is 60 for a leap second, which only some operating systems -support. MINUTE is an integer between 0 and 59. HOUR is an integer +The list has the following nine members: SEC is an integer or +Lisp timestamp representing a nonnegative value less than 60 +\(or less than 61 if the operating system supports leap seconds). +MINUTE is an integer between 0 and 59. HOUR is an integer between 0 and 23. DAY is an integer between 1 and 31. MONTH is an integer between 1 and 12. YEAR is an integer indicating the four-digit year. DOW is the day of week, an integer between 0 and 6, where 0 is Sunday. DST is t if daylight saving time is in effect, nil if it is not in effect, and -1 if daylight saving information is not available. UTCOFF is an integer indicating the UTC offset in -seconds, i.e., the number of seconds east of Greenwich. SUBSEC is -is either 0 or (TICKS . HZ) where HZ is a positive integer clock -resolution and TICKS is a nonnegative integer less than HZ. (Note -that Common Lisp has different meanings for DOW and UTCOFF, and lacks -SUBSEC.) +seconds, i.e., the number of seconds east of Greenwich. (Note that +Common Lisp has different meanings for DOW and UTCOFF, and its +SEC is always an integer between 0 and 59.) -usage: (decode-time &optional TIME ZONE) */) - (Lisp_Object specified_time, Lisp_Object zone) +usage: (decode-time &optional TIME ZONE FORM) */) + (Lisp_Object specified_time, Lisp_Object zone, Lisp_Object form) { struct lisp_time lt = lisp_time_struct (specified_time, 0); struct timespec ts = lisp_to_timespec (lt); @@ -1439,8 +1443,35 @@ usage: (decode-time &optional TIME ZONE) */) year = make_integer_mpz (); } + Lisp_Object hz = lt.hz, sec; + if (EQ (hz, make_fixnum (1)) || !EQ (form, Qt)) + sec = make_fixnum (local_tm.tm_sec); + else + { + Lisp_Object ticks; /* hz * tm_sec + mod (lt.ticks, hz) */ + intmax_t n; + if (FASTER_TIMEFNS && FIXNUMP (lt.ticks) && FIXNUMP (hz) + && !INT_MULTIPLY_WRAPV (XFIXNUM (hz), local_tm.tm_sec, &n) + && ! (INT_ADD_WRAPV + (n, (XFIXNUM (lt.ticks) % XFIXNUM (hz) + + (XFIXNUM (lt.ticks) % XFIXNUM (hz) < 0 + ? XFIXNUM (hz) : 0)), + &n))) + ticks = make_int (n); + else + { + mpz_fdiv_r (mpz[0], + *bignum_integer (&mpz[0], lt.ticks), + *bignum_integer (&mpz[1], hz)); + mpz_addmul_ui (mpz[0], *bignum_integer (&mpz[1], hz), + local_tm.tm_sec); + ticks = make_integer_mpz (); + } + sec = Fcons (ticks, hz); + } + return CALLN (Flist, - make_fixnum (local_tm.tm_sec), + sec, make_fixnum (local_tm.tm_min), make_fixnum (local_tm.tm_hour), make_fixnum (local_tm.tm_mday), @@ -1453,10 +1484,7 @@ usage: (decode-time &optional TIME ZONE) */) ? make_fixnum (tm_gmtoff (&local_tm)) : gmtime_r (&time_spec, &gmt_tm) ? make_fixnum (tm_diff (&local_tm, &gmt_tm)) - : Qnil), - (EQ (lt.hz, make_fixnum (1)) - ? make_fixnum (0) - : Fcons (integer_mod (lt.ticks, lt.hz), lt.hz))); + : Qnil)); } /* Return OBJ - OFFSET, checking that OBJ is a valid integer and that @@ -1487,7 +1515,7 @@ check_tm_member (Lisp_Object obj, int offset) DEFUN ("encode-time", Fencode_time, Sencode_time, 1, MANY, 0, doc: /* Convert TIME to a timestamp. -TIME is a list (SECOND MINUTE HOUR DAY MONTH YEAR IGNORED DST ZONE SUBSEC). +TIME is a list (SECOND MINUTE HOUR DAY MONTH YEAR IGNORED DST ZONE). in the style of `decode-time', so that (encode-time (decode-time ...)) works. In this list, ZONE can be nil for Emacs local time, t for Universal Time, `wall' for system wall clock time, or a string as in the TZ @@ -1496,23 +1524,16 @@ environment variable. It can also be a list (as from without consideration for daylight saving time. If ZONE specifies a time zone with daylight-saving transitions, DST is t for daylight saving time, nil for standard time, and -1 to cause the daylight -saving flag to be guessed. SUBSEC is either 0 or a Lisp timestamp -in (TICKS . HZ) form. +saving flag to be guessed. As an obsolescent calling convention, if this function is called with -6 through 10 arguments, the first 6 arguments are SECOND, MINUTE, -HOUR, DAY, MONTH, and YEAR, and specify the components of a decoded -time. If there are 7 through 9 arguments the *last* argument -specifies ZONE, and if there are 10 arguments the 9th specifies ZONE -and the 10th specifies SUBSEC; in either case any other extra -arguments are ignored, so that (apply #\\='encode-time (decode-time -...)) works. In this obsolescent convention, DST, ZONE, and SUBSEC -default to -1, nil and 0 respectively. - -Out-of-range values for SECOND, MINUTE, HOUR, DAY, or MONTH are allowed; -for example, a DAY of 0 means the day preceding the given month. -Year numbers less than 100 are treated just like other year numbers. -If you want them to stand for years in this century, you must do that yourself. +6 or more arguments, the first 6 arguments are SECOND, MINUTE, HOUR, +DAY, MONTH, and YEAR, and specify the components of a decoded time, +where DST assumed to be -1 and FORM is omitted. If there are more +than 6 arguments the *last* argument is used as ZONE and any other +extra arguments are ignored, so that (apply #\\='encode-time +(decode-time ...)) works. In this obsolescent convention, DST and +ZONE default to -1 and nil respectively. Years before 1970 are not guaranteed to work. On some systems, year values as low as 1901 do work. @@ -1521,27 +1542,27 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */) (ptrdiff_t nargs, Lisp_Object *args) { struct tm tm; - Lisp_Object zone = Qnil, subsec = make_fixnum (0); + Lisp_Object zone = Qnil; Lisp_Object a = args[0]; + Lisp_Object secarg, minarg, hourarg, mdayarg, monarg, yeararg; tm.tm_isdst = -1; if (nargs == 1) { Lisp_Object tail = a; - for (int i = 0; i < 10; i++, tail = XCDR (tail)) + for (int i = 0; i < 9; i++, tail = XCDR (tail)) CHECK_CONS (tail); - tm.tm_sec = check_tm_member (XCAR (a), 0); a = XCDR (a); - tm.tm_min = check_tm_member (XCAR (a), 0); a = XCDR (a); - tm.tm_hour = check_tm_member (XCAR (a), 0); a = XCDR (a); - tm.tm_mday = check_tm_member (XCAR (a), 0); a = XCDR (a); - tm.tm_mon = check_tm_member (XCAR (a), 1); a = XCDR (a); - tm.tm_year = check_tm_member (XCAR (a), TM_YEAR_BASE); a = XCDR (a); + secarg = XCAR (a); a = XCDR (a); + minarg = XCAR (a); a = XCDR (a); + hourarg = XCAR (a); a = XCDR (a); + mdayarg = XCAR (a); a = XCDR (a); + monarg = XCAR (a); a = XCDR (a); + yeararg = XCAR (a); a = XCDR (a); a = XCDR (a); Lisp_Object dstflag = XCAR (a); a = XCDR (a); - zone = XCAR (a); a = XCDR (a); + zone = XCAR (a); if (SYMBOLP (dstflag) && !FIXNUMP (zone) && !CONSP (zone)) tm.tm_isdst = !NILP (dstflag); - subsec = XCAR (a); } else if (nargs < 6) xsignal2 (Qwrong_number_of_arguments, Qencode_time, make_fixnum (nargs)); @@ -1549,18 +1570,37 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */) { if (6 < nargs) zone = args[nargs - 1]; - if (9 < nargs) - { - zone = args[8]; - subsec = args[9]; - } - tm.tm_sec = check_tm_member (a, 0); - tm.tm_min = check_tm_member (args[1], 0); - tm.tm_hour = check_tm_member (args[2], 0); - tm.tm_mday = check_tm_member (args[3], 0); - tm.tm_mon = check_tm_member (args[4], 1); - tm.tm_year = check_tm_member (args[5], TM_YEAR_BASE); + secarg = a; + minarg = args[1]; + hourarg = args[2]; + mdayarg = args[3]; + monarg = args[4]; + yeararg = args[5]; + } + + struct lisp_time lt; + decode_lisp_time (secarg, 0, <, 0); + Lisp_Object hz = lt.hz, sec, subsecticks; + if (FASTER_TIMEFNS && EQ (hz, make_fixnum (1))) + { + sec = lt.ticks; + subsecticks = make_fixnum (0); + } + else + { + mpz_fdiv_qr (mpz[0], mpz[1], + *bignum_integer (&mpz[0], lt.ticks), + *bignum_integer (&mpz[1], hz)); + sec = make_integer_mpz (); + mpz_swap (mpz[0], mpz[1]); + subsecticks = make_integer_mpz (); } + tm.tm_sec = check_tm_member (sec, 0); + tm.tm_min = check_tm_member (minarg, 0); + tm.tm_hour = check_tm_member (hourarg, 0); + tm.tm_mday = check_tm_member (mdayarg, 0); + tm.tm_mon = check_tm_member (monarg, 1); + tm.tm_year = check_tm_member (yeararg, TM_YEAR_BASE); timezone_t tz = tzlookup (zone, false); tm.tm_wday = -1; @@ -1571,25 +1611,17 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */) if (tm.tm_wday < 0) time_error (mktime_errno); - if (CONSP (subsec)) + if (EQ (hz, make_fixnum (1))) + return (CURRENT_TIME_LIST + ? list2 (hi_time (value), lo_time (value)) + : INT_TO_INTEGER (value)); + else { - Lisp_Object subsecticks = XCAR (subsec); - if (INTEGERP (subsecticks)) - { - struct lisp_time val1 = { INT_TO_INTEGER (value), make_fixnum (1) }; - Lisp_Object - hz = XCDR (subsec), - secticks = lisp_time_hz_ticks (val1, hz), - ticks = lispint_arith (secticks, subsecticks, false); - return Fcons (ticks, hz); - } + struct lisp_time val1 = { INT_TO_INTEGER (value), make_fixnum (1) }; + Lisp_Object secticks = lisp_time_hz_ticks (val1, hz); + Lisp_Object ticks = lispint_arith (secticks, subsecticks, false); + return Fcons (ticks, hz); } - else if (INTEGERP (subsec)) - return (CURRENT_TIME_LIST && EQ (subsec, make_fixnum (0)) - ? list2 (hi_time (value), lo_time (value)) - : lispint_arith (INT_TO_INTEGER (value), subsec, false)); - - xsignal2 (Qerror, build_string ("Invalid subsec"), subsec); } DEFUN ("time-convert", Ftime_convert, Stime_convert, 1, 2, 0, diff --git a/test/lisp/calendar/icalendar-tests.el b/test/lisp/calendar/icalendar-tests.el index 060cd8c909..baea480404 100644 --- a/test/lisp/calendar/icalendar-tests.el +++ b/test/lisp/calendar/icalendar-tests.el @@ -477,18 +477,18 @@ icalendar-tests--trim ;; testcase: no time zone in input -> keep time as is ;; 1 Jan 2013 10:00 - (should (equal '(0 0 10 1 1 2013 2 nil 7200 0) + (should (equal '(0 0 10 1 1 2013 2 nil 7200) (icalendar--decode-isodatetime "20130101T100000"))) ;; 1 Aug 2013 10:00 (DST) - (should (equal '(0 0 10 1 8 2013 4 t 10800 0) + (should (equal '(0 0 10 1 8 2013 4 t 10800) (icalendar--decode-isodatetime "20130801T100000"))) ;; testcase: UTC time zone specifier in input -> convert to local time ;; 31 Dec 2013 23:00 UTC -> 1 Jan 2013 01:00 EET - (should (equal '(0 0 1 1 1 2014 3 nil 7200 0) + (should (equal '(0 0 1 1 1 2014 3 nil 7200) (icalendar--decode-isodatetime "20131231T230000Z"))) ;; 1 Aug 2013 10:00 UTC -> 1 Aug 2013 13:00 EEST - (should (equal '(0 0 13 1 8 2013 4 t 10800 0) + (should (equal '(0 0 13 1 8 2013 4 t 10800) (icalendar--decode-isodatetime "20130801T100000Z"))) ) diff --git a/test/lisp/calendar/iso8601-tests.el b/test/lisp/calendar/iso8601-tests.el index 3f1149c864..35c319ed03 100644 --- a/test/lisp/calendar/iso8601-tests.el +++ b/test/lisp/calendar/iso8601-tests.el @@ -24,65 +24,65 @@ (ert-deftest test-iso8601-date-years () (should (equal (iso8601-parse-date "1985") - '(nil nil nil nil nil 1985 nil nil nil nil))) + '(nil nil nil nil nil 1985 nil nil nil))) (should (equal (iso8601-parse-date "-0003") - '(nil nil nil nil nil -4 nil nil nil nil))) + '(nil nil nil nil nil -4 nil nil nil))) (should (equal (iso8601-parse-date "+1985") - '(nil nil nil nil nil 1985 nil nil nil nil)))) + '(nil nil nil nil nil 1985 nil nil nil)))) (ert-deftest test-iso8601-date-dates () (should (equal (iso8601-parse-date "1985-03-14") - '(nil nil nil 14 3 1985 nil nil nil nil))) + '(nil nil nil 14 3 1985 nil nil nil))) (should (equal (iso8601-parse-date "19850314") - '(nil nil nil 14 3 1985 nil nil nil nil))) + '(nil nil nil 14 3 1985 nil nil nil))) (should (equal (iso8601-parse-date "1985-02") - '(nil nil nil nil 2 1985 nil nil nil nil)))) + '(nil nil nil nil 2 1985 nil nil nil)))) (ert-deftest test-iso8601-date-obsolete () (should (equal (iso8601-parse-date "--02-01") - '(nil nil nil 1 2 nil nil nil nil nil))) + '(nil nil nil 1 2 nil nil nil nil))) (should (equal (iso8601-parse-date "--0201") - '(nil nil nil 1 2 nil nil nil nil nil)))) + '(nil nil nil 1 2 nil nil nil nil)))) (ert-deftest test-iso8601-date-weeks () (should (equal (iso8601-parse-date "2008W39-6") - '(nil nil nil 27 9 2008 nil nil nil nil))) + '(nil nil nil 27 9 2008 nil nil nil))) (should (equal (iso8601-parse-date "2009W01-1") - '(nil nil nil 29 12 2008 nil nil nil nil))) + '(nil nil nil 29 12 2008 nil nil nil))) (should (equal (iso8601-parse-date "2009W53-7") - '(nil nil nil 3 1 2010 nil nil nil nil)))) + '(nil nil nil 3 1 2010 nil nil nil)))) (ert-deftest test-iso8601-date-ordinals () (should (equal (iso8601-parse-date "1981-095") - '(nil nil nil 5 4 1981 nil nil nil nil)))) + '(nil nil nil 5 4 1981 nil nil nil)))) (ert-deftest test-iso8601-time () (should (equal (iso8601-parse-time "13:47:30") - '(30 47 13 nil nil nil nil nil nil 0))) + '(30 47 13 nil nil nil nil nil nil))) (should (equal (iso8601-parse-time "134730") - '(30 47 13 nil nil nil nil nil nil 0))) + '(30 47 13 nil nil nil nil nil nil))) (should (equal (iso8601-parse-time "1347") - '(0 47 13 nil nil nil nil nil nil 0)))) + '(0 47 13 nil nil nil nil nil nil)))) (ert-deftest test-iso8601-combined () (should (equal (iso8601-parse "2008-03-02T13:47:30") - '(30 47 13 2 3 2008 nil nil nil 0))) + '(30 47 13 2 3 2008 nil nil nil))) (should (equal (iso8601-parse "2008-03-02T13:47:30Z") - '(30 47 13 2 3 2008 nil nil 0 0))) + '(30 47 13 2 3 2008 nil nil 0))) (should (equal (iso8601-parse "2008-03-02T13:47:30+01:00") - '(30 47 13 2 3 2008 nil nil 3600 0))) + '(30 47 13 2 3 2008 nil nil 3600))) (should (equal (iso8601-parse "2008-03-02T13:47:30-01") - '(30 47 13 2 3 2008 nil nil -3600 0)))) + '(30 47 13 2 3 2008 nil nil -3600)))) (ert-deftest test-iso8601-duration () (should (equal (iso8601-parse-duration "P3Y6M4DT12H30M5S") - '(5 30 12 4 6 3 nil nil nil 0))) + '(5 30 12 4 6 3 nil nil nil))) (should (equal (iso8601-parse-duration "P1M") - '(0 0 0 0 1 0 nil nil nil 0))) + '(0 0 0 0 1 0 nil nil nil))) (should (equal (iso8601-parse-duration "PT1M") - '(0 1 0 0 0 0 nil nil nil 0))) + '(0 1 0 0 0 0 nil nil nil))) (should (equal (iso8601-parse-duration "P0003-06-04T12:30:05") - '(5 30 12 4 6 3 nil nil nil 0)))) + '(5 30 12 4 6 3 nil nil nil)))) (ert-deftest test-iso8601-invalid () (should-not (iso8601-valid-p " 2008-03-02T13:47:30-01")) @@ -94,149 +94,149 @@ (ert-deftest test-iso8601-intervals () (should (equal (iso8601-parse-interval "2007-03-01T13:00:00Z/2008-05-11T15:30:00Z") - '((0 0 13 1 3 2007 nil nil 0 0) - (0 30 15 11 5 2008 nil nil 0 0) + '((0 0 13 1 3 2007 nil nil 0) + (0 30 15 11 5 2008 nil nil 0) ;; Hm... can't really use decode-time for time differences... - (0 30 2 14 3 1971 0 nil 0 0)))) + (0 30 2 14 3 1971 0 nil 0)))) (should (equal (iso8601-parse-interval "2007-03-01T13:00:00Z/P1Y2M10DT2H30M") - '((0 0 13 1 3 2007 nil nil 0 0) - (0 30 15 11 5 2008 nil nil 0 0) - (0 30 2 10 2 1 nil nil nil 0)))) + '((0 0 13 1 3 2007 nil nil 0) + (0 30 15 11 5 2008 nil nil 0) + (0 30 2 10 2 1 nil nil nil)))) (should (equal (iso8601-parse-interval "P1Y2M10DT2H30M/2008-05-11T15:30:00Z") - '((0 0 13 1 3 2007 nil nil 0 0) - (0 30 15 11 5 2008 nil nil 0 0) - (0 30 2 10 2 1 nil nil nil 0))))) + '((0 0 13 1 3 2007 nil nil 0) + (0 30 15 11 5 2008 nil nil 0) + (0 30 2 10 2 1 nil nil nil))))) (ert-deftest standard-test-dates () (should (equal (iso8601-parse-date "19850412") - '(nil nil nil 12 4 1985 nil nil nil nil))) + '(nil nil nil 12 4 1985 nil nil nil))) (should (equal (iso8601-parse-date "1985-04-12") - '(nil nil nil 12 4 1985 nil nil nil nil))) + '(nil nil nil 12 4 1985 nil nil nil))) (should (equal (iso8601-parse-date "1985102") - '(nil nil nil 12 4 1985 nil nil nil nil))) + '(nil nil nil 12 4 1985 nil nil nil))) (should (equal (iso8601-parse-date "1985-102") - '(nil nil nil 12 4 1985 nil nil nil nil))) + '(nil nil nil 12 4 1985 nil nil nil))) (should (equal (iso8601-parse-date "1985W155") - '(nil nil nil 12 4 1985 nil nil nil nil))) + '(nil nil nil 12 4 1985 nil nil nil))) (should (equal (iso8601-parse-date "1985-W15-5") - '(nil nil nil 12 4 1985 nil nil nil nil))) + '(nil nil nil 12 4 1985 nil nil nil))) (should (equal (iso8601-parse-date "1985W15") - '(nil nil nil 7 4 1985 nil nil nil nil))) + '(nil nil nil 7 4 1985 nil nil nil))) (should (equal (iso8601-parse-date "1985-W15") - '(nil nil nil 7 4 1985 nil nil nil nil))) + '(nil nil nil 7 4 1985 nil nil nil))) (should (equal (iso8601-parse-date "1985-04") - '(nil nil nil nil 4 1985 nil nil nil nil))) + '(nil nil nil nil 4 1985 nil nil nil))) (should (equal (iso8601-parse-date "1985") - '(nil nil nil nil nil 1985 nil nil nil nil))) + '(nil nil nil nil nil 1985 nil nil nil))) (should (equal (iso8601-parse-date "+1985-04-12") - '(nil nil nil 12 4 1985 nil nil nil nil))) + '(nil nil nil 12 4 1985 nil nil nil))) (should (equal (iso8601-parse-date "+19850412") - '(nil nil nil 12 4 1985 nil nil nil nil)))) + '(nil nil nil 12 4 1985 nil nil nil)))) (ert-deftest standard-test-time-of-day-local-time () (should (equal (iso8601-parse-time "152746") - '(46 27 15 nil nil nil nil nil nil 0))) + '(46 27 15 nil nil nil nil nil nil))) (should (equal (iso8601-parse-time "15:27:46") - '(46 27 15 nil nil nil nil nil nil 0))) + '(46 27 15 nil nil nil nil nil nil))) (should (equal (iso8601-parse-time "1528") - '(0 28 15 nil nil nil nil nil nil 0))) + '(0 28 15 nil nil nil nil nil nil))) (should (equal (iso8601-parse-time "15:28") - '(0 28 15 nil nil nil nil nil nil 0))) + '(0 28 15 nil nil nil nil nil nil))) (should (equal (iso8601-parse-time "15") - '(0 0 15 nil nil nil nil nil nil 0)))) + '(0 0 15 nil nil nil nil nil nil)))) (ert-deftest standard-test-time-of-day-fractions () ;; decoded-time doesn't support sub-second times. ;; (should (equal (iso8601-parse-time "152735,5") - ;; '(46 27 15 nil nil nil nil nil nil (5 . 10)))) + ;; '(46 27 15 nil nil nil nil nil nil))) ;; (should (equal (iso8601-parse-time "15:27:35,5") - ;; '(46 27 15 nil nil nil nil nil nil (5 . 10)))) + ;; '(46 27 15 nil nil nil nil nil nil))) ) (ert-deftest standard-test-time-of-day-beginning-of-day () (should (equal (iso8601-parse-time "000000") - '(0 0 0 nil nil nil nil nil nil 0))) + '(0 0 0 nil nil nil nil nil nil))) (should (equal (iso8601-parse-time "00:00:00") - '(0 0 0 nil nil nil nil nil nil 0))) + '(0 0 0 nil nil nil nil nil nil))) (should (equal (iso8601-parse-time "0000") - '(0 0 0 nil nil nil nil nil nil 0))) + '(0 0 0 nil nil nil nil nil nil))) (should (equal (iso8601-parse-time "00:00") - '(0 0 0 nil nil nil nil nil nil 0)))) + '(0 0 0 nil nil nil nil nil nil)))) (ert-deftest standard-test-time-of-day-utc () (should (equal (iso8601-parse-time "232030Z") - '(30 20 23 nil nil nil nil nil 0 0))) + '(30 20 23 nil nil nil nil nil 0))) (should (equal (iso8601-parse-time "23:20:30Z") - '(30 20 23 nil nil nil nil nil 0 0))) + '(30 20 23 nil nil nil nil nil 0))) (should (equal (iso8601-parse-time "2320Z") - '(0 20 23 nil nil nil nil nil 0 0))) + '(0 20 23 nil nil nil nil nil 0))) (should (equal (iso8601-parse-time "23:20Z") - '(0 20 23 nil nil nil nil nil 0 0))) + '(0 20 23 nil nil nil nil nil 0))) (should (equal (iso8601-parse-time "23Z") - '(0 0 23 nil nil nil nil nil 0 0)))) + '(0 0 23 nil nil nil nil nil 0)))) (ert-deftest standard-test-time-of-day-zone () (should (equal (iso8601-parse-time "152746+0100") - '(46 27 15 nil nil nil nil nil 3600 0))) + '(46 27 15 nil nil nil nil nil 3600))) (should (equal (iso8601-parse-time "15:27:46+0100") - '(46 27 15 nil nil nil nil nil 3600 0))) + '(46 27 15 nil nil nil nil nil 3600))) (should (equal (iso8601-parse-time "152746+01") - '(46 27 15 nil nil nil nil nil 3600 0))) + '(46 27 15 nil nil nil nil nil 3600))) (should (equal (iso8601-parse-time "15:27:46+01") - '(46 27 15 nil nil nil nil nil 3600 0))) + '(46 27 15 nil nil nil nil nil 3600))) (should (equal (iso8601-parse-time "152746-0500") - '(46 27 15 nil nil nil nil nil -18000 0))) + '(46 27 15 nil nil nil nil nil -18000))) (should (equal (iso8601-parse-time "15:27:46-0500") - '(46 27 15 nil nil nil nil nil -18000 0))) + '(46 27 15 nil nil nil nil nil -18000))) (should (equal (iso8601-parse-time "152746-05") - '(46 27 15 nil nil nil nil nil -18000 0))) + '(46 27 15 nil nil nil nil nil -18000))) (should (equal (iso8601-parse-time "15:27:46-05") - '(46 27 15 nil nil nil nil nil -18000 0)))) + '(46 27 15 nil nil nil nil nil -18000)))) (ert-deftest standard-test-date-and-time-of-day () (should (equal (iso8601-parse "19850412T101530") - '(30 15 10 12 4 1985 nil nil nil 0))) + '(30 15 10 12 4 1985 nil nil nil))) (should (equal (iso8601-parse "1985-04-12T10:15:30") - '(30 15 10 12 4 1985 nil nil nil 0))) + '(30 15 10 12 4 1985 nil nil nil))) (should (equal (iso8601-parse "1985102T235030Z") - '(30 50 23 12 4 1985 nil nil 0 0))) + '(30 50 23 12 4 1985 nil nil 0))) (should (equal (iso8601-parse "1985-102T23:50:30Z") - '(30 50 23 12 4 1985 nil nil 0 0))) + '(30 50 23 12 4 1985 nil nil 0))) (should (equal (iso8601-parse "1985W155T235030") - '(30 50 23 12 4 1985 nil nil nil 0))) + '(30 50 23 12 4 1985 nil nil nil))) (should (equal (iso8601-parse "1985-W155T23:50:30") - '(30 50 23 12 4 1985 nil nil nil 0)))) + '(30 50 23 12 4 1985 nil nil nil)))) (ert-deftest standard-test-interval () ;; A time interval starting at 20 minutes and 50 seconds past 23 ;; hours on 12 April 1985 and ending at 30 minutes past 10 hours on ;; 25 June 1985. (should (equal (iso8601-parse-interval "19850412T232050Z/19850625T103000Z") - '((50 20 23 12 4 1985 nil nil 0 0) - (0 30 10 25 6 1985 nil nil 0 0) - (10 9 11 15 3 1970 0 nil 0 0)))) + '((50 20 23 12 4 1985 nil nil 0) + (0 30 10 25 6 1985 nil nil 0) + (10 9 11 15 3 1970 0 nil 0)))) (should (equal (iso8601-parse-interval "1985-04-12T23:20:50Z/1985-06-25T10:30:00Z") - '((50 20 23 12 4 1985 nil nil 0 0) - (0 30 10 25 6 1985 nil nil 0 0) - (10 9 11 15 3 1970 0 nil 0 0)))) + '((50 20 23 12 4 1985 nil nil 0) + (0 30 10 25 6 1985 nil nil 0) + (10 9 11 15 3 1970 0 nil 0)))) ;; A time interval starting at 12 April 1985 and ending on 25 June ;; 1985. @@ -251,41 +251,41 @@ ;; A time interval of 2 years, 10 months, 15 days, 10 hours, 20 ;; minutes and 30 seconds. (should (equal (iso8601-parse-duration "P2Y10M15DT10H20M30S") - '(30 20 10 15 10 2 nil nil nil 0))) + '(30 20 10 15 10 2 nil nil nil))) (should (equal (iso8601-parse-duration "P00021015T102030") - '(30 20 10 15 10 2 nil nil nil 0))) + '(30 20 10 15 10 2 nil nil nil))) (should (equal (iso8601-parse-duration "P0002-10-15T10:20:30") - '(30 20 10 15 10 2 nil nil nil 0))) + '(30 20 10 15 10 2 nil nil nil))) ;; A time interval of 1 year and 6 months. (should (equal (iso8601-parse-duration "P1Y6M") - '(0 0 0 0 6 1 nil nil nil 0))) + '(0 0 0 0 6 1 nil nil nil))) (should (equal (iso8601-parse-duration "P0001-06") - '(nil nil nil nil 6 1 nil nil nil nil))) + '(nil nil nil nil 6 1 nil nil nil))) ;; A time interval of seventy-two hours. (should (equal (iso8601-parse-duration "PT72H") - '(0 0 72 0 0 0 nil nil nil 0))) + '(0 0 72 0 0 0 nil nil nil))) ;; Defined by start and duration ;; A time interval of 1 year, 2 months, 15 days and 12 hours, ;; beginning on 12 April 1985 at 20 minutes past 23 hours. (should (equal (iso8601-parse-interval "19850412T232000/P1Y2M15DT12H") - '((0 20 23 12 4 1985 nil nil nil 0) - (0 20 11 28 6 1986 nil nil nil 0) - (0 0 12 15 2 1 nil nil nil 0)))) + '((0 20 23 12 4 1985 nil nil nil) + (0 20 11 28 6 1986 nil nil nil) + (0 0 12 15 2 1 nil nil nil)))) (should (equal (iso8601-parse-interval "1985-04-12T23:20:00/P1Y2M15DT12H") - '((0 20 23 12 4 1985 nil nil nil 0) - (0 20 11 28 6 1986 nil nil nil 0) - (0 0 12 15 2 1 nil nil nil 0)))) + '((0 20 23 12 4 1985 nil nil nil) + (0 20 11 28 6 1986 nil nil nil) + (0 0 12 15 2 1 nil nil nil)))) ;; Defined by duration and end ;; A time interval of 1 year, 2 months, 15 days and 12 hours, ending ;; on 12 April 1985 at 20 minutes past 23 hour. (should (equal (iso8601-parse-interval "P1Y2M15DT12H/19850412T232000") - '((0 20 11 28 1 1984 nil nil nil 0) - (0 20 23 12 4 1985 nil nil nil 0) - (0 0 12 15 2 1 nil nil nil 0))))) + '((0 20 11 28 1 1984 nil nil nil) + (0 20 23 12 4 1985 nil nil nil) + (0 0 12 15 2 1 nil nil nil))))) ;;; iso8601-tests.el ends here diff --git a/test/lisp/calendar/parse-time-tests.el b/test/lisp/calendar/parse-time-tests.el index 61a3838a52..7435620b71 100644 --- a/test/lisp/calendar/parse-time-tests.el +++ b/test/lisp/calendar/parse-time-tests.el @@ -28,23 +28,23 @@ (ert-deftest parse-time-tests () (should (equal (parse-time-string "Mon, 22 Feb 2016 19:35:42 +0100") - '(42 35 19 22 2 2016 1 -1 3600 0))) + '(42 35 19 22 2 2016 1 -1 3600))) (should (equal (parse-time-string "22 Feb 2016 19:35:42 +0100") - '(42 35 19 22 2 2016 nil -1 3600 0))) + '(42 35 19 22 2 2016 nil -1 3600))) (should (equal (parse-time-string "22 Feb 2016 +0100") - '(nil nil nil 22 2 2016 nil -1 3600 nil))) + '(nil nil nil 22 2 2016 nil -1 3600))) (should (equal (parse-time-string "Mon, 22 Feb 16 19:35:42 +0100") - '(42 35 19 22 2 2016 1 -1 3600 0))) + '(42 35 19 22 2 2016 1 -1 3600))) (should (equal (parse-time-string "Mon, 22 February 2016 19:35:42 +0100") - '(42 35 19 22 2 2016 1 -1 3600 0))) + '(42 35 19 22 2 2016 1 -1 3600))) (should (equal (parse-time-string "Mon, 22 feb 2016 19:35:42 +0100") - '(42 35 19 22 2 2016 1 -1 3600 0))) + '(42 35 19 22 2 2016 1 -1 3600))) (should (equal (parse-time-string "Monday, 22 february 2016 19:35:42 +0100") - '(42 35 19 22 2 2016 1 -1 3600 0))) + '(42 35 19 22 2 2016 1 -1 3600))) (should (equal (parse-time-string "Monday, 22 february 2016 19:35:42 PST") - '(42 35 19 22 2 2016 1 nil -28800 0))) + '(42 35 19 22 2 2016 1 nil -28800))) (should (equal (parse-time-string "Friday, 21 Sep 2018 13:47:58 PDT") - '(58 47 13 21 9 2018 5 t -25200 0))) + '(58 47 13 21 9 2018 5 t -25200))) (should (equal (format-time-string "%Y-%m-%d %H:%M:%S" (parse-iso8601-time-string "1998-09-12T12:21:54-0200") t) diff --git a/test/src/timefns-tests.el b/test/src/timefns-tests.el index 362e7655a9..13ab7d83c3 100644 --- a/test/src/timefns-tests.el +++ b/test/src/timefns-tests.el @@ -40,25 +40,31 @@ (7879679999900 . 100000) (78796799999999999999 . 1000000000000))) ;; UTC. - (let ((subsec (time-subtract (time-convert look t) - (time-convert look 'integer)))) + (let ((sec (time-add 59 (time-subtract (time-convert look t) + (time-convert look 'integer))))) (should (string-equal (format-time-string "%Y-%m-%d %H:%M:%S.%3N %z" look t) "1972-06-30 23:59:59.999 +0000")) - (should (equal (decode-time look t) - (list 59 59 23 30 6 1972 5 nil 0 subsec))) + (should (equal (decode-time look t 'integer) + '(59 59 23 30 6 1972 5 nil 0))) + (should (equal (decode-time look t t) + (list sec 59 23 30 6 1972 5 nil 0))) ;; "UTC0". (should (string-equal (format-time-string format look "UTC0") "1972-06-30 23:59:59.999 +0000 (UTC)")) - (should (equal (decode-time look "UTC0") - (list 59 59 23 30 6 1972 5 nil 0 subsec))) + (should (equal (decode-time look "UTC0" 'integer) + '(59 59 23 30 6 1972 5 nil 0))) + (should (equal (decode-time look "UTC0" t) + (list sec 59 23 30 6 1972 5 nil 0))) ;; Negative UTC offset, as a Lisp list. (should (string-equal (format-time-string format look '(-28800 "PST")) "1972-06-30 15:59:59.999 -0800 (PST)")) - (should (equal (decode-time look '(-28800 "PST")) - (list 59 59 15 30 6 1972 5 nil -28800 subsec))) + (should (equal (decode-time look '(-28800 "PST") 'integer) + '(59 59 15 30 6 1972 5 nil -28800))) + (should (equal (decode-time look '(-28800 "PST") t) + (list sec 59 15 30 6 1972 5 nil -28800))) ;; Negative UTC offset, as a Lisp integer. (should (string-equal (format-time-string format look -28800) @@ -67,14 +73,18 @@ (if (eq system-type 'windows-nt) "1972-06-30 15:59:59.999 -0800 (ZZZ)" "1972-06-30 15:59:59.999 -0800 (-08)"))) - (should (equal (decode-time look -28800) - (list 59 59 15 30 6 1972 5 nil -28800 subsec))) + (should (equal (decode-time look -28800 'integer) + '(59 59 15 30 6 1972 5 nil -28800))) + (should (equal (decode-time look -28800 t) + (list sec 59 15 30 6 1972 5 nil -28800))) ;; Positive UTC offset that is not an hour multiple, as a string. (should (string-equal (format-time-string format look "IST-5:30") "1972-07-01 05:29:59.999 +0530 (IST)")) - (should (equal (decode-time look "IST-5:30") - (list 59 29 5 1 7 1972 6 nil 19800 subsec))))))) + (should (equal (decode-time look "IST-5:30" 'integer) + '(59 29 5 1 7 1972 6 nil 19800))) + (should (equal (decode-time look "IST-5:30" t) + (list sec 29 5 1 7 1972 6 nil 19800))))))) (ert-deftest decode-then-encode-time () (let ((time-values (list 0 -2 1 0.0 -0.0 -2.0 1.0 @@ -87,11 +97,13 @@ (cons (1+ most-positive-fixnum) 1000000000000) (cons 1000000000000 (1+ most-positive-fixnum))))) (dolist (a time-values) - (let* ((d (ignore-errors (decode-time a t))) + (let* ((d (ignore-errors (decode-time a t t))) + (d-integer (ignore-errors (decode-time a t 'integer))) (e (if d (encode-time d))) - (diff (float-time (time-subtract a e)))) - (should (or (not d) - (and (<= 0 diff) (< diff 1)))))))) + (e-integer (if d-integer (encode-time d-integer)))) + (should (or (not d) (time-equal-p a e))) + (should (or (not d-integer) (time-equal-p (time-convert a 'integer) + e-integer))))))) ;;; This should not dump core. (ert-deftest format-time-string-with-outlandish-zone () @@ -151,7 +163,7 @@ timefns-tests--have-leap-seconds (ert-deftest encode-time-dst-numeric-zone () "Check for Bug#35502." (should (time-equal-p - (encode-time '(29 31 17 30 4 2019 2 t 7200 0)) + (encode-time '(29 31 17 30 4 2019 2 t 7200)) '(23752 27217)))) (ert-deftest float-time-precision () -- 2.17.1 ^ permalink raw reply related [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-07 1:02 ` Paul Eggert 2019-08-07 2:41 ` Stefan Monnier @ 2019-08-07 11:33 ` Lars Ingebrigtsen 2019-08-17 7:54 ` Paul Eggert 2019-08-07 14:44 ` Eli Zaretskii 2 siblings, 1 reply; 45+ messages in thread From: Lars Ingebrigtsen @ 2019-08-07 11:33 UTC (permalink / raw) To: Paul Eggert; +Cc: Eli Zaretskii, andrewjmoreton, emacs-devel Paul Eggert <eggert@cs.ucla.edu> writes: > Eli Zaretskii wrote: >> Was this inspection done on Emacs' own code, or also outside Emacs? > > Lars didn't say. I assume he meant Emacs's own code. Yup. > One alternative would be to leave decode-time's API unchanged from > Emacs 26 and put the new functionality into a new function, say > "time-calendrical". While we're at it, we could call the data > structure that the new function returns a "calendrical timestamp" > instead of a "decoded timestamp", and rename the recently-added > functions make-decoded-time, decoded-time-hour, decoded-time-year > etc. to make-calendrical-time, calendrical-hour, calendrical-year, > etc. I agree; calling these things encoded/decoded time isn't very clear terminology. "calendrical" is a mouthful, though. And "calendar" would imply that it belongs in the calendar package, perhaps... -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-07 11:33 ` Lars Ingebrigtsen @ 2019-08-17 7:54 ` Paul Eggert 2019-08-17 8:16 ` Eli Zaretskii 2019-08-17 20:46 ` Lars Ingebrigtsen 0 siblings, 2 replies; 45+ messages in thread From: Paul Eggert @ 2019-08-17 7:54 UTC (permalink / raw) To: Lars Ingebrigtsen; +Cc: Eli Zaretskii, andrewjmoreton, emacs-devel Lars Ingebrigtsen wrote: > I agree; calling these things encoded/decoded time isn't very clear > terminology. "calendrical" is a mouthful, though. And "calendar" would > imply that it belongs in the calendar package, perhaps... I used "calendrical" rather than "calendar" to try to avoid that implication (also, because os.texi already called these broken-down timestamps "calendrical data"). But perhaps "calendrical" isn't far enough away from "calendar". The POSIX tradition is to call these timestamps "broken-down time", and that is what glibc calls them too. How about if we use that name instead? It would help to be more consistent with other GNU code. ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-17 7:54 ` Paul Eggert @ 2019-08-17 8:16 ` Eli Zaretskii 2019-08-17 9:33 ` Paul Eggert 2019-08-17 20:46 ` Lars Ingebrigtsen 1 sibling, 1 reply; 45+ messages in thread From: Eli Zaretskii @ 2019-08-17 8:16 UTC (permalink / raw) To: Paul Eggert; +Cc: larsi, andrewjmoreton, emacs-devel > From: Paul Eggert <eggert@cs.ucla.edu> > Date: Sat, 17 Aug 2019 00:54:07 -0700 > Cc: Eli Zaretskii <eliz@gnu.org>, andrewjmoreton@gmail.com, emacs-devel@gnu.org > > The POSIX tradition is to call these timestamps "broken-down time", and that is > what glibc calls them too. How about if we use that name instead? It would help > to be more consistent with other GNU code. "Broken-down time" will replace "decoded time", I presume? I think I'm okay with that, but what will we use instead of "encoded time" then? ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-17 8:16 ` Eli Zaretskii @ 2019-08-17 9:33 ` Paul Eggert 0 siblings, 0 replies; 45+ messages in thread From: Paul Eggert @ 2019-08-17 9:33 UTC (permalink / raw) To: Eli Zaretskii; +Cc: larsi, andrewjmoreton, emacs-devel Eli Zaretskii wrote: > "Broken-down time" will replace "decoded time", I presume? I think > I'm okay with that, but what will we use instead of "encoded time" > then? Currently the documentation uses "Lisp timestamp" for encoded timestamps that builtins can return: these are Lisp integers, integer pairs (TICKS . HZ) where HZ is positive, and the traditional four-integer lists (HI LO US PS). The documentation uses the term "time value" for a brader class of timestamps that builtins accept. These are the Lisp timestamps, nil, floats, (HI LO US), and (HI LO). I'm OK with sticking with this terminology, as it hasn't seemed to have been as confusing as "decoded time". As far as I can see, the documentation doesn't use the term "encoded time" which would indeed be confusing. ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-17 7:54 ` Paul Eggert 2019-08-17 8:16 ` Eli Zaretskii @ 2019-08-17 20:46 ` Lars Ingebrigtsen 2019-08-17 20:56 ` Paul Eggert 1 sibling, 1 reply; 45+ messages in thread From: Lars Ingebrigtsen @ 2019-08-17 20:46 UTC (permalink / raw) To: Paul Eggert; +Cc: Eli Zaretskii, andrewjmoreton, emacs-devel Paul Eggert <eggert@cs.ucla.edu> writes: > The POSIX tradition is to call these timestamps "broken-down time", > and that is what glibc calls them too. How about if we use that name > instead? It would help to be more consistent with other GNU code. "Broken-down time" sounds OK to me, although there may be some confusion: Some may assume that it's a faulty time or something. And when we get to the accessor names, it perhaps gets even more potentially confusing: (broken-down-seconds time) (broken-down-zone time) Hm... Perhaps not ideal? -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-17 20:46 ` Lars Ingebrigtsen @ 2019-08-17 20:56 ` Paul Eggert 2019-08-17 21:42 ` Stefan Monnier 0 siblings, 1 reply; 45+ messages in thread From: Paul Eggert @ 2019-08-17 20:56 UTC (permalink / raw) To: Lars Ingebrigtsen; +Cc: Eli Zaretskii, andrewjmoreton, emacs-devel Lars Ingebrigtsen wrote: > "Broken-down time" sounds OK to me, although there may be some > confusion: Some may assume that it's a faulty time or something. Yes, I'm not a big fan of "broken-down time" either. Its main advantages are (1) we can't think of a better name and (2) it's used elsewhere in GNU and POSIX. > And when we get to the accessor names, it perhaps gets even more > potentially confusing: > > (broken-down-seconds time) > (broken-down-zone time) > > Hm... Perhaps not ideal? The POSIX identifier for broken-down time is 'tm', as in 'struct tm'. We could steal that identifier too, e.g., (tm-seconds time), (tm-zone time), etc. Again, not ideal, but perhaps better than (broken-down-seconds time). If the prefix 'tm-' is too short, we could expand it to 'time-tm-' or something like that. ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-17 20:56 ` Paul Eggert @ 2019-08-17 21:42 ` Stefan Monnier 2019-08-17 22:53 ` Paul Eggert 0 siblings, 1 reply; 45+ messages in thread From: Stefan Monnier @ 2019-08-17 21:42 UTC (permalink / raw) To: Paul Eggert; +Cc: Lars Ingebrigtsen, andrewjmoreton, Eli Zaretskii, emacs-devel > The POSIX identifier for broken-down time is 'tm', as in 'struct tm'. We > could steal that identifier too, e.g., (tm-seconds time), (tm-zone time), > etc. Again, not ideal, but perhaps better than (broken-down-seconds > time). If the prefix 'tm-' is too short, we could expand it to 'time-tm-' or > something like that. FWIW, I think neither "broken down time" nor "tm" are significantly less bad than "decoded-time", so I don't think it's worth changing the term we've been using. I think part of the problem is that an "encoded time" object looked like "a list of integers" and a "decoded time" object looked like "a list of integers". As we move the "decoded time" objects closer to actual structs and the "encoded time" objects closer to plain (rational) numbers, things should get more clear. So maybe we should stop documenting "decoded time" objects as being of the form (SEC MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF SUBSEC), but instead say that it's a `decoded-time` object on which you can use the `decoded-time-*` accessors (and provide a corresponding pcase pattern to replace the `(,sec ,minute ...) one). Stefan ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-17 21:42 ` Stefan Monnier @ 2019-08-17 22:53 ` Paul Eggert 2019-08-19 21:12 ` Stefan Monnier 0 siblings, 1 reply; 45+ messages in thread From: Paul Eggert @ 2019-08-17 22:53 UTC (permalink / raw) To: Stefan Monnier Cc: Lars Ingebrigtsen, andrewjmoreton, Eli Zaretskii, emacs-devel Stefan Monnier wrote: > I think neither "broken down time" nor "tm" are significantly less > bad than "decoded-time", so I don't think it's worth changing the term > we've been using. I'm starting to come around to the same feeling. > So maybe we should stop documenting "decoded time" objects as being of > the form (SEC MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF SUBSEC), but > instead say that it's a `decoded-time` object on which you can use > the `decoded-time-*` accessors (and provide a corresponding pcase pattern > to replace the `(,sec ,minute ...) one). That sounds like a reasonable way to move forward. I'm not a pcase expert. How would one go about doing the pcase stuff? That is, how does one provide a pattern so that code like (pcase time ((decoded-time :year y :month m) (some-expr-involving y & m))) can extract the year and month components Y and M from the broken-down time TIME that was created via (make-decoded-time :year y :month m)? Is there an example of doing this sort of thing somewhere? ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-17 22:53 ` Paul Eggert @ 2019-08-19 21:12 ` Stefan Monnier 2019-08-21 10:55 ` Adam Porter 0 siblings, 1 reply; 45+ messages in thread From: Stefan Monnier @ 2019-08-19 21:12 UTC (permalink / raw) To: Paul Eggert; +Cc: Lars Ingebrigtsen, andrewjmoreton, Eli Zaretskii, emacs-devel >> So maybe we should stop documenting "decoded time" objects as being of >> the form (SEC MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF SUBSEC), but >> instead say that it's a `decoded-time` object on which you can use >> the `decoded-time-*` accessors (and provide a corresponding pcase pattern >> to replace the `(,sec ,minute ...) one). > > That sounds like a reasonable way to move forward. > > I'm not a pcase expert. How would one go about doing the pcase stuff? That > is, how does one provide a pattern so that code like (pcase time > ((decoded-time :year y :month m) (some-expr-involving y & m))) can extract > the year and month components Y and M from the broken-down time TIME that > was created via (make-decoded-time :year y :month m)? Is there an example of > doing this sort of thing somewhere? With the cl-defstruct we use for decoded-time, we can already do: (pcase-let (((cl-struct decoded-time (second s) (minute m) hour day) time)) ...) so we could define (pcase-defmacro decoded-time (&rest fields) `(cl-struct decoded-time ,@fields)) OTOH it doesn't work in plain `pcase` currently because of a bug in the `cl-struct` pcase pattern (it expands to code which does (cl-typep XX 'decoded-time) but the way `decoded-time` is defined makes it unusable with `cl-typep`). Stefan ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-19 21:12 ` Stefan Monnier @ 2019-08-21 10:55 ` Adam Porter 2019-08-21 20:20 ` Paul Eggert 0 siblings, 1 reply; 45+ messages in thread From: Adam Porter @ 2019-08-21 10:55 UTC (permalink / raw) To: emacs-devel Forgive me for being late to this discussion. After struggling with using and manipulating date/time values in Emacs, I came up with this: https://github.com/alphapapa/ts.el It's probably not suitable for use in Emacs itself, but in my own packages, it's greatly simplified parsing, manipulating, and accessing timestamp values. I hope that any changes to Emacs's time functions don't break it, because it would require me to add compatibility code. :) But enhancements that improve performance or usability would be great. ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-21 10:55 ` Adam Porter @ 2019-08-21 20:20 ` Paul Eggert 2019-08-26 10:59 ` Adam Porter 0 siblings, 1 reply; 45+ messages in thread From: Paul Eggert @ 2019-08-21 20:20 UTC (permalink / raw) To: Adam Porter; +Cc: emacs-devel Adam Porter wrote: > Forgive me for being late to this discussion. After struggling with > using and manipulating date/time values in Emacs, I came up with this: > > https://github.com/alphapapa/ts.el I looked briefly at it, and don't see any compatibility issues - not that I understand all the code, which depends on packages I don't use. The code's comments say that format-time-string is too slow. What performance issues did you run into? At any rate I think you'll find that this: (string-to-number (format-time-string "%Y" (ts-unix struct))) is more efficient written this way: (nth 5 (decode-time (ts-unix struct))) and I expect you can speed up the code further by caching the entire result of decode-time instead of calling format-time-string for each component. Also, the timestamp functions in Emacs 27 should simplify ts.el, once you can assume Emacs 27. For example, in Emacs 27 you can do something like this: (decoded-time-add X (make-decoded-time :year 10)) to add 10 years to a broken-down timestamp X. One more thing: ts.el's extensive use of float-time is fine for calendrical applications but has limited resolution (2**-22 s or about 2e-7 s for today's timestamps) and so would be problematic for apps requiring higher-resolution timestamps. ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-21 20:20 ` Paul Eggert @ 2019-08-26 10:59 ` Adam Porter 2019-08-26 21:35 ` Paul Eggert 0 siblings, 1 reply; 45+ messages in thread From: Adam Porter @ 2019-08-26 10:59 UTC (permalink / raw) To: emacs-devel Paul Eggert <eggert@cs.ucla.edu> writes: Hi Paul, > I looked briefly at it, and don't see any compatibility issues - not > that I understand all the code, which depends on packages I don't use. Thank you very much for looking at it. > The code's comments say that format-time-string is too slow. What > performance issues did you run into? I didn't necessarily run into problems, but while doing some profiling, I noticed that format-time-string was slower than I expected, so I tried to implement some caching and avoid computing values unnecessarily. You can see some of my primitive test notes, e.g.: https://github.com/alphapapa/ts.el/blob/master/notes.org#accessor-dispatch-vs-string-to-number-format-time-string Some of those benchmarks may be out-of-date with respect to the current code. > At any rate I think you'll find > that this: > > (string-to-number (format-time-string "%Y" (ts-unix struct))) > > is more efficient written this way: > > (nth 5 (decode-time (ts-unix struct))) Thanks, I should have thought of that. > and I expect you can speed up the code further by caching the entire > result of decode-time instead of calling format-time-string for each > component. I do a form of that already in ts-fill by using format-time-string to get all slot values and splitting the resulting string. But that's a good point, I might be able to use decode-time to improve it further. I'll have to do some testing. Thanks. > Also, the timestamp functions in Emacs 27 should simplify ts.el, once > you can assume Emacs 27. For example, in Emacs 27 you can do something > like this: > > (decoded-time-add X (make-decoded-time :year 10)) > > to add 10 years to a broken-down timestamp X. Thanks, I'll have to see if I can make use of those new functions. > One more thing: ts.el's extensive use of float-time is fine for > calendrical applications but has limited resolution (2**-22 s or about > 2e-7 s for today's timestamps) and so would be problematic for apps > requiring higher-resolution timestamps. Right, thanks. My use cases don't involve high-resolution timestamps, so I decided to simplify things by only using Unix timestamp floats. But there is a slot for internal time values, so if that were necessary, the internal implementation could be changed to use them instead. I'm curious, is Emacs fast enough or consistent enough to make use of high-resolution timestamps anyway? I guessed that, with GC pauses, etc., it wouldn't be a suitable platform for such calculations in real-time. Although I guess if the timestamps were from outside Emacs, one could operate on them anyway. Grateful for your feedback! ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-26 10:59 ` Adam Porter @ 2019-08-26 21:35 ` Paul Eggert 0 siblings, 0 replies; 45+ messages in thread From: Paul Eggert @ 2019-08-26 21:35 UTC (permalink / raw) To: Adam Porter; +Cc: emacs-devel Adam Porter wrote: > I'm curious, is Emacs fast enough or consistent enough to make use of > high-resolution timestamps anyway? I guessed that, with GC pauses, > etc., it wouldn't be a suitable platform for such calculations in > real-time. Although I guess if the timestamps were from outside Emacs, > one could operate on them anyway. You're right that calling (current-time) from Elisp won't give you nanosecond accuracy; on my platform, just calling that function takes a few hundred nanoseconds so some error is inherent. You're also right that Emacs isn't suitable for hard real-time applications. As you mention, a common use for Emacs timestamps is to process times generated outside Emacs itself, e.g., file timestamps. On typical POSIXish platforms, file timestamps have nanosecond resolution and range from -2**63 to 2**63 seconds after the epoch, and Emacs can handle all of these timestamps though a few functions like decode-time will probably fail due to limitations of the underlying C libraries. ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-07 1:02 ` Paul Eggert 2019-08-07 2:41 ` Stefan Monnier 2019-08-07 11:33 ` Lars Ingebrigtsen @ 2019-08-07 14:44 ` Eli Zaretskii 2 siblings, 0 replies; 45+ messages in thread From: Eli Zaretskii @ 2019-08-07 14:44 UTC (permalink / raw) To: Paul Eggert; +Cc: larsi, andrewjmoreton, emacs-devel > Cc: larsi@gnus.org, andrewjmoreton@gmail.com, emacs-devel@gnu.org > From: Paul Eggert <eggert@cs.ucla.edu> > Date: Tue, 6 Aug 2019 18:02:30 -0700 > > Although almost all uses of decode-time will be unaffected by the change, > there's little doubt that some user code somewhere will break because it > (mistakenly) assumes that decode-time's result format will never be extended. If > this is a real concern, we can go about the change in some other way. > > One alternative would be to leave decode-time's API unchanged from Emacs 26 and > put the new functionality into a new function, say "time-calendrical". While > we're at it, we could call the data structure that the new function returns a > "calendrical timestamp" instead of a "decoded timestamp", and rename the > recently-added functions make-decoded-time, decoded-time-hour, decoded-time-year > etc. to make-calendrical-time, calendrical-hour, calendrical-year, etc. This > would reduce confusion, as it is harder to remember what a "decoded time" is > than to remember what a "calendrical time" is, at least for me. Also, we could > document that the calendrical data structure may change in future versions, and > that programs should use the new functions rather than inspect the raw data > structure. Another alternative is to make the SECONDS member be a float, then we could return the extra precision there. Would this be a better way to keep backward compatibility? ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-06 1:48 ` Paul Eggert 2019-08-06 14:21 ` Eli Zaretskii @ 2019-08-07 11:41 ` Lars Ingebrigtsen 2019-08-17 9:25 ` Paul Eggert 1 sibling, 1 reply; 45+ messages in thread From: Lars Ingebrigtsen @ 2019-08-07 11:41 UTC (permalink / raw) To: Paul Eggert; +Cc: Andy Moreton, emacs-devel Paul Eggert <eggert@cs.ucla.edu> writes: > OK, after some cogitation I installed something along those lines into > master. I called the new function 'time-convert' by analogy with the > existing functions time-add etc. So now, as you suggested, encode-time > has reverted to its old role of converting from decoded timestamps to > Lisp timestamps and its API is now simpler. Great! Thanks for doing this and adding the sub-second time to the decoded time structure -- I'll be implementing the remaining bits of the ISO 8601 standard in `iso8601-parse' (the ones that deal with fractional seconds) so that we'll have a completely compliant parser. > I didn't follow Stefan's suggestion of adding another function that > acts like current-time except it returns the (TICKS . HZ) format, > because current-time is already planned do exactly that after the next > release (when we will default CURRENT_TIME_LIST to false) and it'll be > simpler if we have one function rather than two that do the same > thing. However, I think this sounds overly ambitious. I think it's likely that there's tons of out-of-tree code that assumes that `current-time' always returns a list of time values, because it's been that way since basically forever. It's been extended, but the first two elements have always been a representation of seconds. This is why I thought it would be good to introduce a new function, say `get-current-time', that could have our new signature. We'd then deprecate `current-time' (but probably never actually remove it since there's so much code out there in the wild that uses it) and rewrite all calls in-tree to use this new function. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-07 11:41 ` Lars Ingebrigtsen @ 2019-08-17 9:25 ` Paul Eggert 2019-08-17 20:51 ` Lars Ingebrigtsen 0 siblings, 1 reply; 45+ messages in thread From: Paul Eggert @ 2019-08-17 9:25 UTC (permalink / raw) To: Lars Ingebrigtsen; +Cc: Andy Moreton, emacs-devel Lars Ingebrigtsen wrote: > I thought it would be good to introduce a new function, say > `get-current-time', that could have our new signature. We'd then > deprecate `current-time' It's not just current-time; it's also encode-time, file-attributes, directory-files-and-attributes, visited-file-modtime, current-idle-time, process-attributes, get-internal-run-time, make-frame-visible, time-add, time-subtract, and no doubt other primitives written in C that make Lisp timestamps visible to user code, along with the many functions written in Lisp (e.g., time-since) that call these primitives and give Lisp timestamps to users. We'd have to come up with new names for all these functions, and all the user-visible variables these functions store into, and deprecate all the old names. And during this deprecation period, Emacs-defined and user-defined code would have to support both old- and new-format timestamps since code could generate either. Of course it would be possible but it'll be easier for everyone concerned if we just bite the bullet at some point - not in the next version of course, but eventually, with an option to not-bite-the-bullet-quite-yet for people who need that option. ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: encode-time vs decode-time 2019-08-17 9:25 ` Paul Eggert @ 2019-08-17 20:51 ` Lars Ingebrigtsen 0 siblings, 0 replies; 45+ messages in thread From: Lars Ingebrigtsen @ 2019-08-17 20:51 UTC (permalink / raw) To: Paul Eggert; +Cc: Andy Moreton, emacs-devel Paul Eggert <eggert@cs.ucla.edu> writes: > Lars Ingebrigtsen wrote: >> I thought it would be good to introduce a new function, say >> `get-current-time', that could have our new signature. We'd then >> deprecate `current-time' > > It's not just current-time; it's also encode-time, file-attributes, > directory-files-and-attributes, visited-file-modtime, > current-idle-time, process-attributes, get-internal-run-time, > make-frame-visible, time-add, time-subtract, and no doubt other > primitives written in C that make Lisp timestamps visible to user > code, along with the many functions written in Lisp (e.g., > time-since) that call these primitives and give Lisp timestamps to > users. Yeah, that's true, so introducing a new function here wouldn't help. But I think that having these functions return something that doesn't have the second spec in car/cadr is going to break a lot of people's out-of-tree code. So my feeling is that your plan isn't feasible, and we'll have to live with these functions returning encoded time on the current form forever. Which I think is OK, although your new format is more elegant. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Support for sub-second time in decoded time 2019-07-29 9:48 Support for sub-second time in decoded time Lars Ingebrigtsen 2019-07-29 14:03 ` Stefan Monnier @ 2019-07-29 14:23 ` Eli Zaretskii 2019-07-29 14:59 ` Lars Ingebrigtsen 2019-07-29 16:46 ` Paul Eggert 2 siblings, 1 reply; 45+ messages in thread From: Eli Zaretskii @ 2019-07-29 14:23 UTC (permalink / raw) To: Lars Ingebrigtsen; +Cc: emacs-devel > From: Lars Ingebrigtsen <larsi@gnus.org> > Date: Mon, 29 Jul 2019 11:48:02 +0200 > > `current-time' returns its data as (HIGH LOW USEC PSEC), but now that we > have bignum support, perhaps we don't need to do it this way. What > about just having a field in decoded times that's the fraction of a > second? That'd be backward-incompatible, no? ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Support for sub-second time in decoded time 2019-07-29 14:23 ` Support for sub-second time in decoded time Eli Zaretskii @ 2019-07-29 14:59 ` Lars Ingebrigtsen 0 siblings, 0 replies; 45+ messages in thread From: Lars Ingebrigtsen @ 2019-07-29 14:59 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: >> From: Lars Ingebrigtsen <larsi@gnus.org> >> Date: Mon, 29 Jul 2019 11:48:02 +0200 >> >> `current-time' returns its data as (HIGH LOW USEC PSEC), but now that we >> have bignum support, perhaps we don't need to do it this way. What >> about just having a field in decoded times that's the fraction of a >> second? > > That'd be backward-incompatible, no? It's an extra field in the structure returned from `decode-time'. There may be callers that rely on it being exactly 8 elements... But I don't think that's very likely? Hm... I guess I could see people saying stuff like (destructuring-bind (....) (decode-time) ) and that would break, but on the other hand, you don't see many people using those constructs in Emacs Lisp code. We could add an optional parameter to `decode-time' INCLUDE-FRACTIONAL-SECONDS and only include the 9th element then. But I think we'd then basically would want to change all callers in Emacs to include that parameter. That's a safer option, though. Either is fine with me. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Support for sub-second time in decoded time 2019-07-29 9:48 Support for sub-second time in decoded time Lars Ingebrigtsen 2019-07-29 14:03 ` Stefan Monnier 2019-07-29 14:23 ` Support for sub-second time in decoded time Eli Zaretskii @ 2019-07-29 16:46 ` Paul Eggert 2019-07-30 11:43 ` Lars Ingebrigtsen 2 siblings, 1 reply; 45+ messages in thread From: Paul Eggert @ 2019-07-29 16:46 UTC (permalink / raw) To: Lars Ingebrigtsen; +Cc: emacs-devel On 7/29/19 4:48 AM, Lars Ingebrigtsen wrote: > Currently, encoded time has support for picoseconds. `decode-time' will > throw away all sub-second time, which makes accurate round-tripping > impossible. No, it's quite possible. Say you want a resolution-R broken-down representation of the Lisp timestamp T. Then you can use (decode-time T) to get the broken-down time in seconds, and (mod (car (encode-time T R)) R) to get the subsecond part. Once you have that, you're off to the races. Admittedly it is not that convenient. We could extend decode-time to accept an additional argument FORM that would let the caller specify the form of the returned value. decode-time could treat FORM much like encode-time does, and encode-time would be extended to grok the new forms so round-tripping would be simpler. This would be upward-compatible with the current behavior. For example, under this proposal we'd have: (setq R 1000000000) (setq X (encode-time nil R)) => (1564418451413082782 . 1000000000) (setq Y (decode-time X nil)) => ((51413082782 . 1000000000) 40 9 29 7 2019 1 t -25200) (equal X (encode-time Y R)) => t ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Support for sub-second time in decoded time 2019-07-29 16:46 ` Paul Eggert @ 2019-07-30 11:43 ` Lars Ingebrigtsen 0 siblings, 0 replies; 45+ messages in thread From: Lars Ingebrigtsen @ 2019-07-30 11:43 UTC (permalink / raw) To: Paul Eggert; +Cc: emacs-devel Paul Eggert <eggert@cs.ucla.edu> writes: > On 7/29/19 4:48 AM, Lars Ingebrigtsen wrote: >> Currently, encoded time has support for picoseconds. `decode-time' will >> throw away all sub-second time, which makes accurate round-tripping >> impossible. > > No, it's quite possible. I meant "round-tripping via the decoded time structure". > Admittedly it is not that convenient. We could extend decode-time to > accept an additional argument FORM that would let the caller specify > the form of the returned value. decode-time could treat FORM much like > encode-time does, and encode-time would be extended to grok the new > forms so round-tripping would be simpler. This would be > upward-compatible with the current behavior. > > For example, under this proposal we'd have: > > (setq R 1000000000) > (setq X (encode-time nil R)) => (1564418451413082782 . 1000000000) > (setq Y (decode-time X nil)) => ((51413082782 . 1000000000) 40 9 29 > 7 2019 1 t -25200) > (equal X (encode-time Y R)) => t As I said in a previous message -- this is very confusing indeed, and I think it should be reworked in a different way before Emacs 27 is released and it's too late to get rid of this confusion. But adding an optional parameter to `decode-time' to also make it include sub-second time in the decoded time structure it returns (also as previously discussed) may be the right thing to do. However, I've grepped through the sources now for usages of decoded time, and it kinda looks to me like adding a ninth slot in decoded time structures would probably not break anything. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 45+ messages in thread
end of thread, other threads:[~2019-08-26 21:35 UTC | newest] Thread overview: 45+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2019-07-29 9:48 Support for sub-second time in decoded time Lars Ingebrigtsen 2019-07-29 14:03 ` Stefan Monnier 2019-07-29 14:12 ` Lars Ingebrigtsen 2019-07-29 14:43 ` Stefan Monnier 2019-07-29 15:00 ` Lars Ingebrigtsen 2019-07-29 17:50 ` Stefan Monnier 2019-07-30 11:33 ` Lars Ingebrigtsen 2019-07-29 16:08 ` encode-time vs decode-time Stefan Monnier 2019-07-30 10:32 ` Lars Ingebrigtsen 2019-07-30 11:34 ` Andy Moreton 2019-07-30 11:37 ` Lars Ingebrigtsen 2019-07-30 17:54 ` Paul Eggert 2019-07-30 22:50 ` Paul Eggert 2019-07-31 19:03 ` Lars Ingebrigtsen 2019-07-31 19:31 ` Stefan Monnier 2019-08-06 1:48 ` Paul Eggert 2019-08-06 14:21 ` Eli Zaretskii 2019-08-06 15:59 ` Paul Eggert 2019-08-06 18:23 ` Eli Zaretskii 2019-08-07 1:02 ` Paul Eggert 2019-08-07 2:41 ` Stefan Monnier 2019-08-07 14:47 ` Eli Zaretskii 2019-08-11 23:39 ` Lars Ingebrigtsen 2019-08-17 6:47 ` Paul Eggert 2019-08-07 11:33 ` Lars Ingebrigtsen 2019-08-17 7:54 ` Paul Eggert 2019-08-17 8:16 ` Eli Zaretskii 2019-08-17 9:33 ` Paul Eggert 2019-08-17 20:46 ` Lars Ingebrigtsen 2019-08-17 20:56 ` Paul Eggert 2019-08-17 21:42 ` Stefan Monnier 2019-08-17 22:53 ` Paul Eggert 2019-08-19 21:12 ` Stefan Monnier 2019-08-21 10:55 ` Adam Porter 2019-08-21 20:20 ` Paul Eggert 2019-08-26 10:59 ` Adam Porter 2019-08-26 21:35 ` Paul Eggert 2019-08-07 14:44 ` Eli Zaretskii 2019-08-07 11:41 ` Lars Ingebrigtsen 2019-08-17 9:25 ` Paul Eggert 2019-08-17 20:51 ` Lars Ingebrigtsen 2019-07-29 14:23 ` Support for sub-second time in decoded time Eli Zaretskii 2019-07-29 14:59 ` Lars Ingebrigtsen 2019-07-29 16:46 ` Paul Eggert 2019-07-30 11:43 ` Lars Ingebrigtsen
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.