LabVIEW Idea Exchange

cancel
Showing results for 
Search instead for 
Did you mean: 
0 Kudos
Bob_Schor

Fix TimeStamp Control and Indicator to allow all reasonable values (means changing the "unwired" value, I suspect)

Status: Declined

Any idea that has not received any kudos within a year after posting will be automatically declined. 

I was recently developing some teaching material involving "time arithmetic", and (re-)discovered some peculiar anomalies with the LabVIEW TimeStamp Control and Indicator.  LabVIEW's TimeStamp is defined as "the number of seconds since midnight, 1 Jan 1904, UTC".  It is represented internally as a 128-bit number, with the first 64 bits being the number of seconds, and the second 64 bits being "fractional seconds".  If you subtract two TimeStamps, you get the "elapsed time" between them, which (if it is less than a day) is easily displayed by converting the resulting Dbl to a TimeStamp and wiring it to a TimeStamp indicator.  You need to set the Indicator to display 24-hour UTC (and no date), otherwise you'll get "local time".  In particular, if I wire the constant 0 into a Convert to TimeStamp and display this in EST, I (should) get 19:00:00.

 

Instead, I get 00:00:00!  If I wire 1 (second), I get the expected 19:00:01, and if I wire -1, I get 18:59:59.  I can get very-very close to 0 (0.0000000000001), and I'll get 19:00:00, but 0 gives me a "big jump" to 0:00:00.  This is something mathematicians call a "discontinuity".

 

I called NI, spoke to an AE, and he seemed as surprised by this (unexpected, perhaps even undocumented) behavior.  He was, however, able to find a report where someone else mentioned this, and the LabVIEW Developers chose to "leave it as it is" (no explanation that he could provide).  I've been puzzling over this, and can find only one explanation (for which I have a suggested "fix") --

 

LabVIEW Variables have a default (or "unwired") value, frequently 0.  For a TimeStamp, 0 mean "midnight, 1 Jan 1903", which I can understand will look "silly" as the "default" value of the TimeStamp control.  The current unwired appearance of the TimeStamp is a time of 0:00:00 PM, and an unspecified date (MM/DD/YYYY) on my machine.  This is also what is displayed when 0 is wired to it.  However, this is also the value displayed when either +inf, -inf, or NaN is wired to it.  Of course, wiring the Machine epsilon (the smallest non-zero real) produces 7 PM, the Disconcerting Discontinuity.

 

I maintain that, in the case of a TimeStamp Control or Indicator, a better "unwired" value would be NaN, which will currently give a "legal" display that is meaningful, i.e. a time of 0 (regardless of the time zone) and no specific date.  This would allow NI to restore the ability to let all dates and times display on a continuous scale, with the displayed value of -1 showing a second earlier than the displayed value of 0, as expected.

 

Recommendation -- restore the value 0 as a "legal" TimeStamp value (displaying the equivalent of midnight, 1 Jan 1904 in accordance with the TimeStamp display format) and choose a different value, perhaps NaN, as the "unwired default".  I cannot imagine that this would seriously "break" code, as it only affects the displayed value.  However, having the display exhibit a "display discontinuity" as the TimeStamp value crosses 0 seems illogical and confusing, particularly for those trying to learn to use TimeStamps.

 

Bob Schor

17 Comments
tst
Knight of NI Knight of NI
Knight of NI

I tend to agree that 0 should ideally be displayed correctly, but like the LV devs, I'm not at all sure I would want this changed now. In practice, this has never bothered me.

 

I think the problem in your case stems from your use of the timestamp indicator to displayed elapsed time. The timestamp indicator is meant to display the timestamp data type, which by definition is in absolute time, not relative time. You want to display relative time, so what you should do is take a regular numeric indicator, right click it, select Display Format... and change the display to relative time. You can even click the advanced radio button at the bottom to edit the content of the display more.

 

Once you do that, and assuming you don't actually want to display a date of 1904, I think your problem should go away.


___________________
Try to take over the world!
Bob_Schor
Knight of NI

Yes, I agree that one could make a distinction between Absolute Time (which uses a TimeStamp) and Relative Time (which is simply a "number of seconds", hence should be a Dbl).  This might even be discussed somewhere, the distinction between Absolute and Relative Time, but it is a concept that bears emphasizing to one's students.  I'll keep that in mind in my teaching.

 

Meanwhile, I see zero "harm" in making the (logical) change -- I cannot see how it would "break" any code, and might even make it more robust by having an "uninitialized TimeStamp" announce itself programmatically, instead of just visually.  As it stands, the only way to recognize it is to see that the Front Panel shows a date of MM/DD/YYYY (though you could "test for zero", I suppose), but having a NaN pop up in your code should be a Big Fat Clue, one you can easily trap with the Not a Number/Path/Refnum? function.

 

And, wearing my Math Hat, there's something to be said for logic, consistency, and continuity in numeric Controls and Indicators.

 

BS

AristosQueue (NI)
NI Employee (retired)

So you are asking for us to change the behavior of "To Time Stamp" such that zero maps to 1904, which means we would apply this mutation to all block diagrams when they upgrade:

Mutate.png

 

I think I get that part.  But then you started asking for a change to the default value for Time Stamp controls/indicators. I didn't understand that part at all. Why does that need to change?

 

Regardless of whether that needs to change or not, tou seem to be operating under the belief that those two 64-bit numbers are doubles. They arent't. They are uInt64s. There's no bit pattern that corresponds to NaN. There's no way to introduce a NaN value at this point beyond the one we already have as there is no mutation that could possibly be applied. We would have to introduce a brand new Time Stamp 2 data type and deprecate all existing APIs -- not upgrade, deprecate -- that use time stamp, which would include waveform and variant. Not going to happen.

 

So, summary: mutation totally doable for the conversion bullet. mutation totally not doable if you really do think we need to change the defintion of the timestamp data type.

Bob_Schor
Knight of NI

Sorry for the imprecise language.  I am well aware of the 128-bit representation, and it was sloppy to call it "Dbl" (if you subtract two TimeStamps, you get a Dbl).  The point I was trying to make was you do not need to make the change you outline -- there is no reason to treat 0 as a "special number" (unless you want the display to look different).

 

I cooked up this example.  For ease of entry, I'm representing the TimeStamp as a cluster of two I64s (which lets me specify -1 easier).  I chose -1 (seconds), 0, and +1, convert each to a TimeStamp value, then use a TypeCast to show the internal representation. What I'm arguing for is to allow the 0 representation to "look like" the other two, i.e. to display as 7:00:00.000 PM, 12/31/1903.  If you want the (pardon my pejorative phrase) "illogical" display that basically hides the date and time corresponding to this perfectly good value, you can achieve it by testing for zero and substituting, as you illustrated, NaN.  I just don't understand why you would want to do that, what the utility of such a display would be.

 

In trying to "come up with a reason" for this behavior, I surmised (probably incorrectly) that this choice was made to clue LabVIEW users who saw such an "inconsistent" display, one that didn't indicate a date and time when the program was run, that nothing was wired to the TimeStamp indicator.  I note that most variables take the "unwired" value of 0, and display it accordingly.  I was only suggesting that if you want to "have your cake and eat it, too", and continue to show "unwired" as "no date and time", you could accomplish this by using NaN as the "unwired" value.  But that's a detail -- I think seeing a 1903 (or 1904 -- depends on your time zone) date in your TimeStamp indicator (if you change it so 0 displays what I would argue as the "correct" date and time) would be a sufficient "clue" to the user that the indicator was unwired.

 

TimeStamp Block Diagram.pngTimeStamp Front Panel.png

  

AristosQueue (NI)
NI Employee (retired)

> (unless you want the display to look different)

 

And we definitely do. There is a use case for visually identifying a control that has never had a valid date entered. I do not work on this data type, so I don't know the details, but I did find some comments in the history for this use case of the time stamp. 1904 may be a rarely used date, but it is possibly a valid date. So the data type has a way to differentiate "no date" from "epoch date actually entered". And having such a value was considered useful for the data type itself. Thus the data type has a "not really a date" value. Now, the implementation of that value is one that you really shouldn't know -- that's part of the private implementation of the time stamp. It exists.

 

The only place where you interact with that zero is in the "To Time Stamp" node, which, as I said, does seem like something we could improve to remove the discontinuity.

 

In otherwords, in your picture above, the double value zero could map to 1904 and we would *still* be using "0,0" inside the Time Stamp data type to represent "no date set". No user of the the Time Stamp API would be any the wiser.

 

Tangent:

Until just now, I had no idea that the Type Cast primitive even worked on Time Stamp. I'm slightly horrified to see the private data exposed like that -- especially since I know the underlying private data was changed at least once in the past, which would have broken code like that. I definitely would never use that casting. As I've said many times, "If LabVIEW crashes, it means R&D screwed up except for two situations: calling external code and using the Type Cast node." Users are able to do all sorts of things with those two nodes that aren't good practices but sometimes work for some situations. This won't cause a crash, but it is an API that could break in the future and/or introduce hard to figure out logic errors. It works today, but if someone decided to change the Time Stamp to have 256 bits of information for some reason, the Type Cast would break (or turn into a weird coercion) but the entire rest of the Time Stamp API would keep working. Likewise, if the value of the "not a date" was changed to be, say, MaxUInt64, that would introduce a logical fault in code using the Type Cast. You're peeking into the private data.

Brian_Powell
Active Participant

To my knowledge, the private data for the time stamp has not changed since we created it.  I know of no plans to change it, and we intentionally gave it more resolution and more range than we thought we would need for several years.  (Isn't the resolution down below the atto-second range?)  I'm not promising that we'll never change it, but I'm not particularly alarmed by exposing it through Type Cast.

 

Recall that with NaN on IEEE 754 floating point numbers, there's an actual bit pattern that represents NaN.  (Actually, there are several of them.)  So that means that they are giving up being able to represent certain legal values in order to represent certain illegal (or non-numeric) values.  In the interest of not changing current behavior, I would say that our NaN for the Time Stamp is a 64.64 number that is all zeros.  We would have to choose some pattern of 128 bits, so why not make it zeros?  There are about 2^128 other candidates for this NaT(ime) bit pattern, but I'm not convinced any are better than all zeros.  Note that I am also not in favor of adding a 129th bit, for the sake of covering all existing use cases plus NaT.

 

I think tst's comment about using a regular numeric to display elapsed time is a good idea.  The time stamp control and indicator are best used for absolute, not relative, time.

Bob_Schor
Knight of NI

All of these are good points, and (probable) reasons my suggestion is not going to go anywhere.  I will pick up on something AristosQueue said, that 1904 is a valid date.  However, I still cannot set a TimeStamp control to 7 pm on 31 Dec 1903 (in my time zone) because that's the internal "Time Zero".  So I can set a TimeStamp to almost any date and time I want, except one -- doesn't that bother anyone?

 

Please forgive me for "looking under the covers".  Many years ago, when I was trying to figure out how Time and TimeStamps worked (if memory serves, I was trying to get LabVIEW's TimeStamp and Microsoft Excel's version to agree, not easy to do), I committed the Deadly Sin of using TypeCast (goes back to my experience with Fortran's Equivalence declaration).

 

One of the reasons I was originally using the TimeStamp indicator to display elapsed time was that I didn't know you could display a Dbl as a time -- tst's comment was very instructive on that issue, and I plan to incorporate this additional knowledge in both my code and my teaching.

 

BS

tst
Knight of NI Knight of NI
Knight of NI

> So I can set a TimeStamp to almost any date and time I want, except one -- doesn't that bother anyone?

 

Only in principle. In practice, I couldn't care less because it's a date I'm never going to use. It doesn't bother me any more than the timestamp's apparent unwillingness to display dates past the year 3000 (which is actually a real concern if I have do Futurama related time calculations 😉 ).


___________________
Try to take over the world!
tst
Knight of NI Knight of NI
Knight of NI

> It works today, but if someone decided to change the Time Stamp to have 256 bits of information for some reason, the Type Cast would break

 

Well, you are going to have to fix the Y584B bug at some point...


___________________
Try to take over the world!
Darin.K
Trusted Enthusiast

>  In the interest of not changing current behavior, I would say that our NaN for the Time Stamp is a 64.64 number that is all zeros.  We would have to choose some pattern of 128 bits, so why not make it zeros?  There are about 2^128 other candidates for this NaT(ime) bit pattern, but I'm not convinced any are better than all zeros.  Note that I am also not in favor of adding a 129th bit, for the sake of covering all existing use cases plus NaT.

 


IEEE754 "throws away" a few valid values to represent +/-0, +/- Inf and the various NaN flavors.  You can count them on your hands.  The timestamp indicator is tossing many, many values, I am not going to do the math to count them.  Any value which has an absolute value less than somewhere around 5e-20 is going to be considered NaT.  Besides this you toss out any date which is prior to January 1601 or quite pessimistically, any value after the year 3000.

 

The ship has sailed so I do not advocate fixing this.  But I think it raises an important consideration when choosing sentinel values in the future.  I agree with Brian that you lose a potential legal value when you choose to add a special value, but I strongly disagree that all 2^128 values were created equal.  Zero is special in its own right (integer, common default value), and falls into the range of displayable, and therefore valid date ranges. 

 

I'd just add epsilon to all DBL values myself if I faced this.  I guess I have never looked at data which crossed the epoch boundary, and happened to exactly hit it...