Because openHAB 3.x rules now use Java Time API instead of Jodatime, there is a new DateTime Conversion thread for openHAB 3.x.
Overview
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 notablynow
. -
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 along
. 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"
when
Time cron "0 */1 * ? * *" // every minute. Source: https://crontab.guru/examples.html
then
// 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 https://www.openhab.org/docs/administration/logging.html#logging-into-separate-file)
val StringBuilder myLogMessage = new StringBuilder
myLogMessage.append( "\n" + "\n" + " ---------- myJodaNow (JodaDateTime) to substring - examples ---------- Source: http://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html" + "\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 http://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html" + "\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: http://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html
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 http://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html
#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")