DateTime Conversion (openHAB 2.x)

Tags: #<Tag:0x00007efec969e8c0> #<Tag:0x00007efec969e7d0> #<Tag:0x00007efec969e6e0>

Because openHAB 3.x rules now use Java Time API instead of Jodatime, there is a new DateTime Conversion thread for openHAB 3.x.


In openHab 2.x there are different ways to handle Date/Time values.

  • DateTimeType
    A DateTime Item carries a DateTimeType.

  • Joda DateTime
    By default openHAB 2.x-Rules use a Joda DateTime class to represent time, most notably now.

  • Epoch
    The lowest common denominator when working with time is to get at the epoc value. Epoc is the number of milliseconds that has passed since 1 January 1970 GMT and stored in a long. With epoc, one can compare two dates together, convert a Joda DateTime to a DateTimeType and visa versa. With epoc you can represent a duration.

  • String
    In certain cases it is needed to convert date/time values to a human readable.

This flow chart is intended to help you easily find the code needed for conversion.
The numbers of the flow chart refer to the numbers of the following list.

#1 Get DateTimeType from String

String must be ISO 8601 formatted like this: “yyyy-MM-dd’T’HH:mm:ss.SSSZ”

val DateTimeType MyDateTimeTypeFromString = DateTimeType.valueOf(MyString) 

#2 Get DateTimeType from Epoch

Regarding to the flow chart this code converts Epoch => #6 => to Joda => #11 => to String => #1 => to DateTimeType

val DateTimeType MyDateTimeTypeFromEpoch = new DateTimeType(new DateTime(MyEpoch).toString)

#3 Get DateTimeType from Joda

Variant A

val calendar = java.util.Calendar::getInstance
calendar.timeInMillis = now.millis
val MyDateTimeTypeFromJoda_VariantA = new DateTimeType(calendar)

Variant B

(probably less efficient but much easier to read and remember)

Because Joda DateTime and DateTimeType both accept ISO 8601 formatted date/time strings it is easy to convert from one to the other using their toString.
Regarding to the flow chart this code converts Joda => #11 => to String => #1 => to DateTimeType

val MyDateTimeTypeFromJoda_VariantB = new DateTimeType(now.toString)

#4 Get Joda from DateTimeType

Varinat A

val MyJodaFromDateTimeType_VariantA = new DateTime((MyDateTimeItem.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)

Variant B

Because Joda DateTime and DateTimeType both accept ISO 8601 formatted date/time strings it is easy to convert from one to the other using their toString.
Regarding to the flow chart this code converts DateTimeType => #12 => to String => #5 => to Joda

val MyJodaFromDateTimeType_VariantB = new DateTime(MyDateTimeItem.state.toString)

#5 Get Joda from String

String must be ISO 8601 formatted like this: “yyyy-MM-dd’T’HH:mm:ss.SSSZ”

Varinat A

val DateTime MyJodaFromStringV1 = new DateTime("2018-05-05T05:55:55.000-04:00")

Varinat B

val DateTime MyJodaFromStringV2 = parse("1963-01-01T00:00:00")

#6 Get Joda from Epoch

Varinat A

val MyJodaFromEpoch = new DateTime(MyEpoch)

Variant B
If the Epoch value is stored in a NumberItem, this NumberItem must be converted to Epoch first.

var MyEpochFromNumberItem = (MyNumberItem.state as Number).longValue * 1000
val MyJodaFromNumberItem = new DateTime(MyEpochFromNumberItem)

#7 Get Epoch from Joda

val Number MyEpochFromJoda = now.millis

#8 Get Epoch from DateTimeType

Varinat A

val Number MyEpochFromDateTimeTypeItem_VariantA = (MyDateTimeTypeItem.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli

Varinat B

val Number MyEpochFromDateTimeTypeItem_VariantB = new DateTime(MyDateTimeTypeItem.state.toString).millis

#9 Get Epoch from String

String must be ISO 8601 formatted like this: “yyyy-MM-dd’T’HH:mm:ss.SSSZ”

val Number MyEpochFromString = new DateTime(MyDateTimeString).millis

#10 Get String from Epoch

Variant A
Regarding to the flow chart this code converts Epoch => #6 => to Joda => #11 => to String. This means formatting can be done like shown in #11

val String MyStringFromEpoch_VariantA = new DateTime(MyEpoch).toString

Variant B

Here is an option utilizing SimpleDateFormat:

import java.text.SimpleDateFormat
import java.util.Date

val SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
val String MyStringFromEpoch_VariantB = sdf.format(new Date(MyEpoch))

#11 Get String from Joda

This will return a time in your local timezone.

Variant A

This gives you the complete ISO 8601 DateTime-string. (“yyyy-MM-dd’T’HH:mm:ss.SSSZ”)

val String MyStringFromJoda = now.toString

Variant B

Using patterns you can get a substring that exactly fits to your needs.

val String MyStringFromJoda = now.toString("yyyy-MM-dd'T'HH:mm:ss.SSSZ")

Copy&Paste example, to use a pattern

Copy this complete code into a rules.file. The code shows how patterns are used and …

rule "rJodaDateTimeToSubstring_Examples"
	Time cron "0 */1 * ? * *" // every minute. Source:
    // first prepare the log entry
        val String          myLogFile = "mySeparateLogFile"   // if 'mySeparateLogFile' does not exist, logging goes into openhab.log (to create a separate logfile see
        val StringBuilder   myLogMessage = new StringBuilder
        myLogMessage.append( "\n" + "\n" + " ----------   myJodaNow (JodaDateTime) to substring - examples   ----------    Source:" + "\n" + "\n" )

    // second create a JodaDateTime we can work with 
        val DateTime myJodaNow = now  
        myLogMessage.append( "    myJodaNow = " + myJodaNow.toString + "\n" + "\n" ) 

    // then use pattern to get the desired substring
        myLogMessage.append( "     pattern  name                          substring" + "\n" )
        myLogMessage.append( "     -------  ----                          ---------" + "\n" )
        myLogMessage.append( "        G     era                         = " + myJodaNow.toString("G") + "\n" )
        myLogMessage.append( "        C     century of era (>=0)        = " + myJodaNow.toString("C") + "\n" )
        myLogMessage.append( "        Y     year of era (>=0)           = " + myJodaNow.toString("Y") + "\n" )
        myLogMessage.append( "        yyyy  Year                        = " + myJodaNow.toString("yyyy") + "\n" )
        myLogMessage.append( "        yyy   Year                        = " + myJodaNow.toString("yy") + "\n" )
        myLogMessage.append( "        MMMM  Month                       = " + myJodaNow.toString("MMMM") + "\n" )
        myLogMessage.append( "        MMM   Month                       = " + myJodaNow.toString("MMM") + "\n" )
        myLogMessage.append( "        MM    Month                       = " + myJodaNow.toString("MM") + "\n" )
        myLogMessage.append( "        M     Month                       = " + myJodaNow.toString("M") + "\n" )
        myLogMessage.append( "        w     week of weekyear            = " + myJodaNow.toString("w") + "\n" )
        myLogMessage.append( "        D     day of year                 = " + myJodaNow.toString("D") + "\n" )
        myLogMessage.append( "        e     day of week                 = " + myJodaNow.toString("e") + "\n" )
        myLogMessage.append( "        EEE   day of week                 = " + myJodaNow.toString("EEEE") + "\n" )
        myLogMessage.append( "        E     day of week                 = " + myJodaNow.toString("E") + "\n" )
        myLogMessage.append( "        dd    Day                         = " + myJodaNow.toString("dd") + "\n" )
        myLogMessage.append( "        d     Day                         = " + myJodaNow.toString("d") + "\n" )
        myLogMessage.append( "        a     halfday of day              = " + myJodaNow.toString("a") + "\n" )
        myLogMessage.append( "        K     hour of halfday (0~11)      = " + myJodaNow.toString("K") + "\n" )
        myLogMessage.append( "        h     clockhour of halfday (1~12) = " + myJodaNow.toString("h") + "\n" )
        myLogMessage.append( "        H     hour of day                 = " + myJodaNow.toString("H") + "\n" )
        myLogMessage.append( "        k     clockhour of day (1~24)     = " + myJodaNow.toString("k") + "\n" )
        myLogMessage.append( "        mm    minute of hour              = " + myJodaNow.toString("mm") + "\n" )
        myLogMessage.append( "        m     minute of hour              = " + myJodaNow.toString("m") + "\n" )
        myLogMessage.append( "        ss    second of minute            = " + myJodaNow.toString("ss") + "\n" )
        myLogMessage.append( "        s     second of minute            = " + myJodaNow.toString("s") + "\n" )
        myLogMessage.append( "        z     time zone                   = " + myJodaNow.toString("z") + "\n" )
        myLogMessage.append( "        ZZZ   time zone offset/id         = " + myJodaNow.toString("ZZZ") + "\n" )
        myLogMessage.append( "        ZZ    time zone offset/id         = " + myJodaNow.toString("ZZ") + "\n" )
        myLogMessage.append( "        Z     time zone offset/id         = " + myJodaNow.toString("Z") + "\n" )
        myLogMessage.append( "        German date string 1              = " + myJodaNow.toString("EEEE, d. MMMM yyyy") + "\n" ) 
        myLogMessage.append( "        German date string 2              = " + myJodaNow.toString("dd.MM.yyyy") + "\n" ) 
        myLogMessage.append( "\n" + "    More patterns see" + "\n" )

    // finally, write the log-entry into the log-file 
        logInfo( myLogFile, myLogMessage.toString )

end // EndOfRule rJodaDateTimeToSubstring_Examples

… and creates an entry in openhab.log with the resulting substrings.

 ----------   myJodaNow (JodaDateTime) to substring - examples   ----------    Source:

    myJodaNow = 2019-02-03T07:16:00.067+01:00 

     pattern  name                          substring
     -------  ----                          ---------
        G     era                         = n. Chr.
        C     century of era (>=0)        = 20
        Y     year of era (>=0)           = 2019
        yyyy  Year                        = 2019
        yyy   Year                        = 19
        MMMM  Month                       = Februar
        MMM   Month                       = Feb
        MM    Month                       = 02
        M     Month                       = 2
        w     week of weekyear            = 5
        D     day of year                 = 34
        e     day of week                 = 7
        EEE   day of week                 = Sonntag
        E     day of week                 = So
        dd    Day                         = 03
        d     Day                         = 3
        a     halfday of day              = AM
        K     hour of halfday (0~11)      = 7
        h     clockhour of halfday (1~12) = 7
        H     hour of day                 = 7
        k     clockhour of day (1~24)     = 7
        mm    minute of hour              = 16
        m     minute of hour              = 16
        ss    second of minute            = 00
        s     second of minute            = 0
        z     time zone                   = MEZ
        ZZZ   time zone offset/id         = Europe/Berlin
        ZZ    time zone offset/id         = +01:00
        Z     time zone offset/id         = +0100
        German date string 1              = Sonntag, 3. Februar 2019
        German date string 2              = 03.02.2019

    More patterns see

#12 Get String from DateTimeType

Formatting can be done like shown here.
For more details look at this.

val String MyStringFromDateTimeType = MyDateTimeType_item.state.format("%1$td.%1$tm.%1$ty %1$tH:%1$tM")
DateTime Conversion (openHAB 3.x)
[SOLVED] DateTime Items compare against fixed DateTimes
How to format the persistence previousState().timestamp?
[SOLVED] createTimer (tomorrow noon) in a rule
OH2.4 #1428 Java 8 DateTime API
Type Conversions
Openhab: How to show only the day from a "date-String"
Converting a Timer value
Display NTP binding to unix timestamp
String to DateTime
Item label and variables
Needing help with formats in a rule
Needing help with formats in a rule
Another rule not triggering with astro
Could not invoke method: BusEvent.postUpdate(java.lang.String,java.lang.String) on instance: null
Timer Widget / Countdown Widget with Alexa (Date Difference)
How convert a german date string to datetime format
How convert a german date string to datetime format
Unifi Client Datetime Format
now.isAfter rule
[SOLVED] Epoch Number to Integer
[Solved] Demo sitemap issue - Outside Weather text colour
Feeling rusty... compare two times?
Rules: Initialization of var DateTime fails; => How to solve?
Rule: Start Action with Alexa Alarm
Rule: Start Action with Alexa Alarm
isBefore no longer works?
Variable Wakeup-Time Sequence
Trying to use format in rules
[SOLVED] How to move timeDate to item in a rule?
Design Pattern: Time Of Day
Format DateTime in frontail/rules
[SOLVED] Openhab DateTime
Fire for TIME IS Rule
[SOLVED] Rule to convert Time to String
[SOLVED] Lambda Functions or similar: Create an array / map to iterate through to send 'timed' commands
Time formating
DateTime type when input string does not match
DateTime to epoch rule example?
[SOLVED] Rule: Calc end time from start time and duration
How to assign lastUpdate to an item?
Time and Date Formatting in openHAB
Rule example - compare two times
Compare two TimeDate types
Compare two TimeDate types
Graph from independent data points
[SOLVED] Sending datetime to an item
[SOLVED] Assign value from string to Joda time format
[SOLVED] DateTime functions cannot be invoked
How to convert DateTime-Item (DateTimeType) to DateTime in rules
[SOLVED] Epoch time without milliseconds
Problem with MQTT - How to configure the item?
How to convert DateTime-Item (DateTimeType) to DateTime in rules
[SOLVED] Rule question with multiple "whens" + "last seen option"
[Solved] OH2: time calculations -- doing my head in
AlarmClock Item from openHAB Android App
Comparing Dates for a group of items (Zigbee devices)
Condition between x time and y time
Known issues on OH3 upgrade


That’s something we should definitely improve and contribute back to the docs when it has filled some of the todos.

A way to do it would be:

val DateTimeType timestamp = new DateTimeType(new DateTime(epoch).toString)

NOTE: Because Joda DateTime and DateTimeType both accept ISO8601 formatted date/time strings it is easy to convert from one to the other using their toString.

There are other ways I’m sure. For example, #3 is basically doing just that. Just replace now.millis with epoch that you got some other way.

I recommend:

val dtt = new DateTimeType(now.toString)

It is probably less efficient but much easier to read and remember.

val readableString = now.toString

Creates the same format as in #1.

val joda = new DateTime(epoch)

Another alternative:

val Number epochFromDateTimeType = new DateTime(MyDateTimeItem.state.toString).millis

Assuming it is ISO 8601 format:

val epoch = new DateTime(MyTimestampString).millis

If it is in ISO 8601 format (as illustrated in the example)

val String MyTimestampString = new DateTime(epoch).toString

Otherwise see 11 for how to adjust the outputted format.

See previous example. To format it:

val String MyTimestampString = now.toString("yyyy-MM-dd'T'HH:mm:ss.SSSZ")

See for full documentation on the format string which I think matches those for SimpleDateFormat.

I haven’t tested any of these but am pretty sure they are all correct. There may be a typo here and there though.


Thank you very much!
I will test it.

Hi, i get the string from a webpage and can´t use it as datetime inside openhab:

2018-10-25 11:00

(The whole string is “2018-10-26 11:00 Uhr”, so i cutted out the charcters 0 to 16.)

How can i convert this into a datetime item?

My rule is:

rule "Pollen datetime"
    Item DWD_Pollen_last_update changed or
    System started
    PollenLastUpdateDateTime.postUpdate(DWD_Pollen_last_update.state.toString().substring(0, 16))

But this doesn´t work, because of the wrong string format, i think? The “T” is missing between date and time?

This is my error:

Cannot convert '2018-10-25 11:00' to a state type which item 'PollenLastUpdateDateTime' accepts: [DateTimeType, UnDefType].

Could you make your OP a wiki, so that we can add the different solutions provided to the OP, please?

I am trying to convert from a Human-Readable String to epoch which I have troubles with to read as it does not seem to be in ISO format, how can I specify the format?

I’m not sure regular users have the permissions necessary to turn their post into a wiki. @anfaenger, if you don’t have that option under the three dots menu let me know and I can do it. As a moderator I have that power <evil laugh>.

1 Like

I have much less experience with this. Personally I’d do some String manipulation to convert it to ISO8601 format. See for how to do it with Java core classes and for how to do it with Joda.

This are the options I have:

I will insert all the suggestions to my first post on the weekend.

If you want I can make it a wiki for you.

Yes please.
Maybe a stupid question: What does this mean?
Couldn’t find anything about it in the docs.

1 Like

A wiki will make the posting editable by anyone.

I’ll make the change right now. I can always change it back.

1 Like

Feel free to ping me, when we are ready to move this to the documentation.

I will help then.
But @rlkoshak is already experienced with moving content to the docs anyway. :slight_smile:

1 Like

Hi @vzorglub,
Just realized, that I’ve been working on the first post and in the meantime you edited it too.
Sorry if I messed up something. I will try to fix it. How can I notice this in the future.

Don’t worry go ahead

I don’t think one can…

This is #11 instead of #5, right?

Looking back I see no difference between 5 and 11. Duplicates?

#5 should get joda from string
#11 should get string from joda

I like #5 :wink::

val DateTime dateTimeFromString = new DateTime("2018-05-05T05:55:55.000-04:00")

Be careful with #11, since it will return a time in your local timezone if done like dateTime.toString.

Here’s one that doesn’t really fit anywhere, but it’s very handy… and the easiest way I’ve found to manually define a specific Joda DateTime.

val DateTime fiveDay =,55,55,0)