Pulling my hair out with Date and Time -- help!

Tags: #<Tag:0x00007f61736a0668>

Going round and round and getting nowhere with DateTime, so figured it was time to ask.

First off, how do I convert (or even cast!) from an org.joda.time.DateTime object to an openhab DateTime object and back again? (Since apparently they’re different things, and so far never the two shall meet.)

Secondly, what I’m trying to do is write code to compare now with astro objects. Basically, “is it before dawn?”, “is it after dusk?”, that type of thing. Eventually I want to be able to answer the question “is right now between dawn and dusk?”

Here’s what I have so far, that doesn’t work:

(items)
// these work as advertised, and give openhab DateTime objects with dawn and dusk
DateTime VIRTUAL_DAWN_DATETIME "Dawn starts at [%1$tH:%1$tM]" (Group_Virtual)  {astro="planet=sun,type=civilDawn,property=start"}
DateTime VIRTUAL_DUSK_DATETIME "Dusk starts at [%1$tH:%1$tM]" (Group_Virtual) {astro="planet=sun,type=civilDusk,property=start"}


(rules)
// this is fine...
var org.joda.time.DateTime TempDateTime1 


rule "whatever"
when
    System started
then
   {
      //  this attempted conversion from org.openhab.core.library.items.DateTimeItem to org.joda.time.DateTime is apparently not allowed.  How can I convert between the two that obviously should be cross compatible?
      TempDateTime1 = VIRTUAL_DAWN_DATETIME


      // this comparison doesn't work, gets flagged as incompatible types; figure this is another case of above conversion not happening
      if (now.getMillis() < VIRTUAL_DAWN_DATETIME)
         {
            // do stuff!
         }

      // this comparison doesn't work, gets flagged as has no idea what to do with .getmillis() on VIRTUAL_DAWN_DATETIME
      if (now.getMillis() < VIRTUAL_DAWN_DATETIME.getMillis())
         {
            // do stuff!
         }

      
      // this comparison doesn't work either.  says incompatible types
        if (now.isBefore(VIRTUAL_DAWN_DATETIME))
            {
              // do stuff
            }
}

So how the %$@Q#%^@#$^@#^ do you do date/time comparisons then!?? I’ve bent this thing over backwards and upside down, and ARAGH!

I’ve tried searching the wiki and posts, but I keep finding examples that don’t work when posted verbatim into rules (or items, as the case may be), so I’m really stuck.

Thanks in advance!

Two more permutations that don’t work:

// can't resolve reference to "<"
if (now < VIRTUAL_DAWN_DATETIME)
            {
                
            }

// incompatible types.  joda DateTime refuses to play with openhab DateTimeItem.           
if (now.isBefore(VIRTUAL_DAWN_DATETIME))
            {
                
            }

Yeah, it’s confusing. Here is an example that compares these two different things, by taking the state of a DateTime item and creating a Joda DateTime object from it. From there, comparisons are easy.

I implemented something similar in a previous openHAB setup that I did, and then I ended up using the astro actions instead of the astro binding.

Here is what I did:

import org.openhab.core.library.types.*
import org.openhab.model.script.actions.*
import org.joda.time.*

rule "Daylight"
when
	System started
then
	logInfo("Daylight", "Recalculating")

	var DateTime Sunrise = new DateTime(getAstroSunriseEnd(now.toDate, lat, lon))
	logInfo("Daylight", "Sunrise ends at " + Sunrise)

	var DateTime Sunset = new DateTime(getAstroSunsetStart(now.toDate, lat, lon))
	logInfo("Daylight", "Sunset starts at " + Sunset)

	// Determine if it is currently daylight outside
	if ((Sunrise.isBeforeNow()) && (Sunset.isAfterNow())) {
		logInfo("Daylight", "It is currently daylight outside.")
		postUpdate(cDaylight, OPEN) // OPEN = TRUE
	}
	else {
		logInfo("Daylight", "It is currently dark outside.")
		postUpdate(cDaylight, CLOSED) // CLOSED = FALSE
	}
}

Hope this helps!

Here is a rule I use to do a similar calculation that I use when OH starts up to determine what time of day it is:

val Functions$Function3 updateTimeOfDay = [String tod, String ptod, boolean update |
        logInfo("Weather", "Setting PreviousTimeOfDay to \"" + ptod + "\" and TimeOfDay to \"" + tod + "\"")
        if(update) {
                TimeOfDay.postUpdate(tod)
                PreviousTimeOfDay.postUpdate(ptod)
        }
        else {
                TimeOfDay.sendCommand(tod)
                PreviousTimeOfDay.sendCommand(ptod)
        }
]

rule "Get time period for right now"
when
        System started
then
    val morning = now.withTimeAtStartOfDay.plusHours(6).millis
        val sunrise = new DateTime((Sunrise_Time.state as DateTimeType).calendar.timeInMillis)
        val twilight = new DateTime((Twilight_Time.state as DateTimeType).calendar.timeInMillis)
        val evening = new DateTime((Sunset_Time.state as DateTimeType).calendar.timeInMillis)
        val night = now.withTimeAtStartOfDay.plusHours(23).millis

        if(now.isAfter(morning) && now.isBefore(sunrise))       updateTimeOfDay.apply("Morning", "Night", true)
        else if(now.isAfter(sunrise) && now.isBefore(twilight)) updateTimeOfDay.apply("Day", "Morning", true)
        else if(now.isAfter(twilight) && now.isBefore(evening)) updateTimeOfDay.apply("Twilight", "Day", true)
        else if(now.isAfter(evening) && now.isBefore(night))    updateTimeOfDay.apply("Evening", "Twilight", true)
        else                                                    updateTimeOfDay.apply("Night", "Evening", true)
end

My trick is I convert everything to epoc milliseconds which now is able to handle in its comparisons. In the rest of my rules I use the value of TimeOfDay and PreviousTimeOfDay to make decisions based on what time it is.

1 Like

Thanks Rich (and everybody else!), this really helped!

I wound up appropriating your method of casting to millis; it allows me to do mathematical comparisons the way I’m expecting to.

I keep feeling like I only have one conversion direction (time in millis to DateTimeType), but maybe that’s just because the code hasn’t quite settled into my brain enough where I truly understand what I’m doing here.

I’m not quite sure what you mean by one direction. You can create a new Date, DateTime, or DateTimeType from epoc millis if you need to go the other direction. Way deep down inside, that is how all of these classes store it.

OK, so back at this… It’s definitely not sinking in after a sleep on it.

now is a(n openhab) DateTime type. How do I cast that to millis, so that I can do math with it? now.timeInMillis doesn’t work, and neither does now.calendar.timeInMillis .

That’s what I mean about one direction; I can get things TO openhab’s DateTime type, I just can’t go back from an openhab DateTime to raw millis.

@$%!%# it’s now.millis. Oh well, thanks anyway!

Did you see the example I linked?

I did! Unfortunately you were being too helpful for your own good. :smiley: That example is a better way to answer the question is now between dusk and dawn. But I need the ability to calculate with time itself for a bunch of my rules; the particular question was only my learning vehicle. If ya know what I mean!

1 Like