Gauge for Length of Day (showing Solstices & Equinoxes)


For fun, I just ran a few numbers…

From the equator, on a typical day, in 12 seconds,
the sun can appear to travel about 3.5 miles to the west.

(based on Earths circumference / 24 = 1,038 mph)

This also means the farther away from the equator, the less miles per second from your perspective.
(IE: At latitude 60, that 12 seconds equates to about 1.75 miles)


Interesting thought experiment. I wasn’t able to get into the full logic of the API but it appears to be calculating based on lat/long so theoretically more accurate to physical location?

Anyway, today, the sunrise API is 14 seconds earlier than the TWC data, north-west at approximately 2.2 miles is a weather station. Plugging in those coordinates into the API = almost identical data to the twc data (1 sec) :exploding_head:.


If that is the right station, and we reverse engineer my previous formula, that estimates your GPS latitude somewhere between 36 and 44 degrees. (either north or south)

Note, I am not trying to blast your personal info here…
I’m just making a playful guess based on partial data.

I bet with a few days worth of data, we could estimate the latitude within one degree.
(however, longitude will never be revealed unless you also included the actual times…
… and even then, it would only tell you how far east/west in any given timezone)

I thought SmartThings captured GPS coords when determining our Home location.
(Although I wonder at what level of precision that data is passed to $twcweather requests)



ST does captured those coordinates. Based on our little experiment, if they are passed to $twcweather, they are only being used to determine the closest station.


Just to follow up on this from a few days ago. As I studied the numbers it appeared my DLP was still not changing daily. Digging in, I found that, even though I got all the times down to seconds, webcore still wouldn’t do all the right math with those times and was truncating. So I converted my shortest and longest day to seconds for the multiplier and then current day all using your formula and now I get (I think) a more accurate number. Today it says I am at 99.82% of max. Makes sense since max should be in a few days. Thanks!


This was probably the most frustrating part of this piston.
(and is why I now do all of my math based on integer seconds instead of Time)


I’m sure you already knew this but I find it interesting that webcore can do the correct calculations
for a dynamic variable but not for a time or datetime variable. I put together a quick piston.

with these inputs:


and using the same formula:

I get these three results:

If we could just convert the dynamic variable directly to seconds it would be great. As soon as you do anything with time, seconds are truncated.


So which of the nine types is dynamic representing in this case?


The only possibility I see is perhaps a string…
(since military time is not on the list)


Regardless of what it represents, the math on the two time variables is done correctly down to the second. Perhaps the real question is what is it casting those two time variables into to be able to do the math properly when it can’t do it for an actual time variable?


Honestly, I think it comes down to Time variables do not like to store seconds, LOL
(meaning a ‘dumb’ sting retains the most accurate answer)

In other words, I suspect the math is done properly in all of your examples, but the storage canister for Time is restrictive.

To test this, you can convert that perfect string into Time, and watch the seconds disappear…


I believe the time variable doesn’t have a problem with storing seconds. In fact I believe I have narrowed the issue down to the cast function from string to time (or datetime). I created the test piston below and it shows whenever you cast from string to time, seconds are lost. Casts from time to integer (see seconds and milliseconds calculation) or integer to time (see ‘…S’ variables) retain the seconds. Note when there is not cast (’…NF’ variables) the seconds are also retained. Also, in answer to your question above, the dynamic version is using string because that is the output of formatDuration. In the case of dynamic data, no cast is performed.


And now, sorry for diverging so much from the real topic of this thread.

I noticed an issue with my length of day. Everything is calculating correctly based on $twcweather sunrise and sunset values but when I go look at for today, the daylength is off. I noticed this because watching the DLP (mine currently 99.86%) it did not seem like I was going to make it to 100% by Saturday which should be the summer solstice. Currently based on $twc, I get a day length of 14:36:47. When I look at, it indicated that day length should have been two days ago:

Anyone else observe similar discrepancies?

Side note: I also notice the longest day this year is one second more than what I had recorded when I created this piston.


Although in truth, you have another conversion in there…

(Time - Time) … Convert answer into a string … and then convert string into a Time variable … or
(Time - Time) … Convert answer into a string … and then convert into a DateTime variable

In other words, the only time the seconds were dropped is when you tried to do multiple conversions in one line of code…

PS, I might play around with your test piston if there was a green import code handy…


Length of day from is based on Cities or Zip Codes… but I’m not sure how far apart are their sensors, or how well the land in between is calculated.

Length of day in this piston is based on the sunrise and sunset times as passed from $twcweather. This is a separate entity, so their sensor locations and variances in between also come into play.

… and lastly, we should remember that dayLength changes nearly comes to a stand-still near the Solstices. (actually coming to a dead stop on the Solstice, before reversing)

This last bit means that, a 20 second station offset (3-4 miles?) can appear to be data from 2 days in the past or future, IF you compare near a Solstice…

What I recommended 6 months ago, I would also recommend for this Saturday…

This way, we can force in yearly high & low numbers that align with TWC’s data.


The green code for that piston is 6ara

True, I was looking at the final conversion from string to dynamic, time, or datetime. It is not as obvious what else is going on. formatDuration creates a string in a particular format given an input but not clear where the conversion happens in that process. The fact that the formatDuration conversion works, however, could be shown by the success of the dynamic type assignment where it accepts the output ‘as-is’.


I saw that and, unfortunately missed out 6 months ago. I just added in yesterday logging the day length to google sheets (since I had that worked out :slight_smile:). Now I can’t miss the shortest/longest days in the future. And I can do plots!


You can still do a partial calibration this Saturday.
(IE: tweak June’s high for now… You can tweak December’s low later… Likely only a few seconds)

I had to shift my DecLow 6 seconds… I am curious as to what my JunHigh will shift.
(my dlp% is currently 100.03%, or 4 sec above max)


When I originally created this piston, I scanned the next 15 years in the future, and while the day of month changed often, the max and min dayLengths were all within 2 sec of each other. (most within 1 sec)

I went with the extreme values, with the intention of preventing the dial from ever going outside of 0 - 100%.
… but I still think calibration is wise to bring balance between the two sources.


I added in a block of code just to compare last short/long vs each days value and update as needed. At least I know it will always be accurate.

In reference to the variable conversions, I updated my piston to manually calculate all data points in ms (decimal). I don’t use time at all. Using formatDuration only to get a conventionally formatted string (xx:xx:xx) for quick visual reference.


I wonder if this is related… I create an EVERY block:


… which spits out this code:


(notice the missing seconds and beyond)