Datetime conversion issue

Hi Guys,
I am pulling a "last_seen" tag (datetime in a string datatype) from a json object coming from an MQTT server.

In Ignition I have a referance tag that points to the MQTT tag, it has an on value change event script that runs when this value updates.

from datetime import datetime

<There is a bunch of other code here not relevant - will post if required. >

# If date time convert string to datetime object
if key == "last_seen":
	print "The time string is " + value[0]
	value2 = [datetime.strptime(value[0], '%Y-%m-%dT%H:%M:%S+11:00')]
	print "The time conversion is " + str(value2[0])
	system.tag.writeBlocking(path,value2)
else: 
	system.tag.writeBlocking(path,value)

The print output is:

The time string is 2022-10-13T18:59:11+11:00
The time conversion is 2022-10-13 18:59:11

But the datetime tag vaule is "2022-10-14 05:59:11.0" as you can see it is 23 hours ahead.

I have checked the MQTT and the Igntion servers OS and both are set for the same time and time zone.

The correct tag is written to when this runs, the value is just wrong

I am unsure why there is this discrepancy, here.

Ignition maker 8.1.14

Convert time from str is always little bite tricky.
If you have java.date in input and you want convert it in datetime, just do that:

from datetime import datetime
dt =  datetime.fromtimestamp(yourJavaDate.getTime()/1000.0)

But if you absolutely want to parse the date from the string, it's more complex.
In your script you intentionally omit the timezone (+11:00), which explains your difference.

value2 = [datetime.strptime(value[0], '%Y-%m-%dT%H:%M:%S+11:00')]

strptime supports %z for timezone only from python 3.2 onwards, so you need to create your own parser.
You can use this script to do that:

from datetime import datetime, timedelta, tzinfo

class FixedOffset(tzinfo):
    """Fixed offset in minutes: `time = utc_time + utc_offset`."""
    def __init__(self, offset):
        self.__offset = timedelta(minutes=offset)
        hours, minutes = divmod(offset, 60)
        #NOTE: the last part is to remind about deprecated POSIX GMT+h timezones
        #  that have the opposite sign in the name;
        #  the corresponding numeric value is not used e.g., no minutes
        self.__name = '<%+03d%02d>%+d' % (hours, minutes, -hours)
    def utcoffset(self, dt=None):
        return self.__offset
    def tzname(self, dt=None):
        return self.__name
    def dst(self, dt=None):
        return timedelta(0)
    def __repr__(self):
        return 'FixedOffset(%d)' % (self.utcoffset().total_seconds() / 60)


def convertStrDateToDatetime(date_str):	
	naive_date_str = date_str[0:-6]
	offset_str = date_str[-6:]
	naive_dt = datetime.strptime(naive_date_str, '%Y-%m-%dT%H:%M:%S')
	offset = int(offset_str[-5:-3])*60 + int(offset_str[-2:])
	if offset_str[0] == "-":
	   offset = -offset
	dt = naive_dt.replace(tzinfo=FixedOffset(offset))
	return dt


date_str = "2022-10-13T18:59:11+11:00"      
print "The time string is " + date_str + " " + str(type(date_str))

convert = convertStrDateToDatetime(date_str)
print "The time conversion is " + str(convert) + " " + str(type(convert))

Source come from

https://stackoverflow.com/questions/1101508/how-to-parse-dates-with-0400-timezone-string-in-python/23122493#23122493

1 Like

Don't use jython's datetime module. It is buggy, particularly when using non-US timezones. Use java's classes (and the Ignition system.date.* functions).

3 Likes

The 'T' is not a valid character in system.date.parse(). OffsetDateTime can parse it, though. Then we can convert it to an Instant and then to a Date.

from java.time import OffsetDateTime
from java.util import Date

timeIn = '2022-10-13T18:59:11+11:00'

t = OffsetDateTime.parse(timeIn).toInstant()

timeOut = Date.from(t)

Output for me, since I'm in the Eastern Time Zone

Thu Oct 13 03:59:11 EDT 2022
3 Likes

Thank you, for the fresh set of eyes. I should have worked out it was in UTC time; I did even tried applying the %z at one point.

Important life lesson don't code past midnight. :man_facepalming:

Thank you, this is a clean solution.

Gotta thank you so much for a little blurb you said in another post that stated that Ignition uses java date objects as this allowed me to skip all the super frustrating datetime.strptime() junk when trying to parse a date from a web_dev call. Once I found that I looked up this post and grabbed the relevant java code and things worked so much easier. Thanks!

1 Like