How to get the designer timezone context to match the gateway timezone context, instead of UTC?

Is there a way to set the designer timezone context to match the gateway timezone context? ... and is there a reason it does not?

On my system executing system.date function using the designer Script Console defaults to using UTC, whereas the same script when run from the gateway context default to using the configured gateway timezone (CDT). This difference in behavior is baffling to me and a hinderance to testing. Is it a feature or a flaw?

In my mind running a script from the designer scripting console should assume the gateway context (and timezone) and output the same as if run in a gateway event script but that doesn't appear to be the case.

Example script:

TestDate = system.date.getDate(2022, 8, 4)
print 'Test Date: {}'.format(today)
now = system.date.now()
print 'Now: {}'.format(now)
print 'DayOfMonth: {}'.format(system.date.getDayOfMonth(now))
print 'Hour of day: {}'.format(system.date.getHour24(now))

Results from designer script console:

>>> 
Today: Sun Sep 04 00:00:00 UTC 2022
Now: Tue Oct 04 20:44:03 UTC 2022
DayOfMonth: 4
Hour of day: 20

Results from gateway timer script (pulled from wrapper.log), not exactly time synced:

INFO   | jvm 1    | 2022/10/04 16:03:59 | Today: Sun Sep 04 00:00:00 CDT 2022
INFO   | jvm 1    | 2022/10/04 16:03:59 | Now: Tue Oct 04 16:03:59 CDT 2022
INFO   | jvm 1    | 2022/10/04 16:03:59 | DayOfMonth: 4
INFO   | jvm 1    | 2022/10/04 16:03:59 | Hour of day: 16

Note the difference in output of the system.date functions system.date.getDate, system.date.getHour24 etc..

My specific use case is attempting to determine a date (date-time) for the start of a day and one for the end of the same day, allowing for 23 hour and 25 hour days due to daylight savings. To use as a range for a historical data query and export. I need to trigger a script shortly after midnight and automatically export data for the previous day (23-25 hours) to a set of files. I need that to run in the context of the gateway's local time not UTC.
My development/testing started using the script console and I was struggling to get the right date math to work out when everything was defaulting to UTC, then later realized the scripts behaved differently when run from the gateway context (gateway events).

Ignition 8.1.19

Similarly timestamps shown in the designer tag browser use UTC rather than local time (though the timezone is not indicated at all. Is there anyway to control the timezone and format of those.
image

Java (and therefore Ignition gateway, vision client, and designer) loads the local machine's timezone on startup. There are project properties that can override this.

Since java.util.Date, the underlying data type Ignition uses, is based on UTC milliseconds, transferring across the network retains the "instant-in-time" meaning. This is fundamental and crucial to proper operation of Ignition. Dates and times are converted to local time when converted to string, and converted from localtime when parsing strings and assembling from date/time fragments.

If you must, you can override conversions on a per-object basis with java's LocalDateTime datatype.

2 Likes

Thanks for the response.

Contrary to your statement above, my observations show that the designer does not appear to use the machines local timezone at all, but instead shows all timestamps in UTC. That is why its easy to get confused when looking at the System>CurrentDateTime and System>Timezone tags in designer as the date and time are shown in UTC time, and are not shown using the server's configured Timezone.
Reference: Get gateway Time through scritping - #13 by PGriffith

Yes, I understand that all ignition date objects (java.util.Date) are really just milliseconds since unix epoch. What I am trying to understand is why the designer context (tag browser and script console) defaults to applying UTC timezone when the gateway context defaults to applying the server's timezone. I'd expect it would make more sense to apply the server timezone for display of dates in the designer.

When it comes to scripting and date math this difference in timezone context is more significant than just formatting display of a date (milliseconds since unix epoch) as a string.

As an example, here is a script that finds and prints the start and end of the day that contains the date/time provided as a parameter. The function defined as a gateway script but changes behavior based on whether it is called from script console or a gateway event script: shared.date.printDayStartEnd(paramDate=None)

def printDayStartEnd(paramDate=None):
	# CAUTION: this script returns different date values dependant on context
	# - Designer context: assumes UTC (e.g. script console)
	# - Gateway Context: assumes the OS timezone (e.g. gateway events)
	
	# use date parameter if provided, if not assume now
	myDate = paramDate if (paramDate is not None) else system.date.now()
	
	# determine start and end dates (date-time), days may be 23-25 hours dependant on DST 
	myYear = system.date.getYear(myDate)
	myMonth = system.date.getMonth(myDate)
	myDayOfMonth = system.date.getDayOfMonth(myDate)
	startDate = system.date.getDate(myYear, myMonth, myDayOfMonth)
	endDate = system.date.addDays(startDate, 1)
	
	print 'Start: {} End: {} Hours: {}'.format(startDate, endDate, system.date.hoursBetween(startDate, endDate))

Function calls:

shared.date.printDayStartEnd(system.date.getDate(2022, 2, 13)) # DST Start
shared.date.printDayStartEnd(system.date.getDate(2022, 10, 6)) # DST End
shared.date.printDayStartEnd()

Results when function calls are run from designer context (script console):

>>>
Start: Sun Mar 13 00:00:00 UTC 2022 End: Mon Mar 14 00:00:00 UTC 2022 Hours: 24
Start: Sun Nov 06 00:00:00 UTC 2022 End: Mon Nov 07 00:00:00 UTC 2022 Hours: 24
Start: Tue Oct 04 00:00:00 UTC 2022 End: Wed Oct 05 00:00:00 UTC 2022 Hours: 24
>>>

Results when function calls are run from gateway context (gateway timer script), output to wrapper.log:

Start: Sun Mar 13 00:00:00 CST 2022 End: Mon Mar 14 00:00:00 CDT 2022 Hours: 23
Start: Sun Nov 06 00:00:00 CDT 2022 End: Mon Nov 07 00:00:00 CST 2022 Hours: 25
Start: Tue Oct 04 00:00:00 CDT 2022 End: Wed Oct 05 00:00:00 CDT 2022 Hours: 24

Note the difference in the hours for each day, as UTC interpretation of dates does not use any DST adjustment. In this case I want the date math to include DST adjustments resulting in 23-25 hour days.

So, I understand the difference in behavior, but I'm not clear on the "why", whether that difference is intentional on the part of the ignition developers and whether there might be good rationale for keeping that difference... other than UTC representation of dates provides uniqueness that DST aware representations do not.

If there is not known intentional rationale for the difference, I'd make the following suggestions to ignition developers:

  1. Have the designer assume the same timezone context as the gateway context by default. For display of date values and scripted date math.
  2. For scripting, provide means to set the timezone context that applies to date object creation, date math (add/subtract) and date formatting.
  3. If you plan to keep UTC representation of dates in designer, show the timezone text 'UTC' as part of the formatted date representation for date values in the tag browser to help alleviate potential confusion.

Did you even look in project properties?

My designer does not behave at all like yours, nor like any I know. Except for people who've configured their local system to do so. So too with the gateway.

And, local timezone in the designer and Vision client are long-established behaviors that your proposal would break.

You can already control the gateway timezone by the gateway machine's own timezone, or via ignition.conf parameter, effective after gateway restart.

You can already produce any desired timezone behavior on a case-by-case basis using java's LocalDateTime with an explicit timezone (particularly useful with Perspective scripting).

I don't know what you've done to screw it up, but the rest of us don't have your problem. You might need support to look over your shoulder to figure it out.

Edit: And, you cannot set a context for string conversions for java.util.Date. It is a global setting in java, not subject to change. You must use LocalDateTime to apply TZ on a case-by-case basis.

Also, if you set your gateway to use a local time, Ignition's scripting functions like system.date.addDays() will deliver 23 or 25 hour deltas crossing daylight savings changes.

Thanks for pointing out the LocalDateTime object, I'll have to look closer at that. I suppose I expected similar functionality to be available through system.date member functions and don't see reason why it couldn't be added.

Absolutely, I have looked at project properties. I'll look again, but feel free to point out if I missed something obvious.

My proposal doesn't suggest modifying the behavior of the gateway/client context at all, I'm just suggesting that designer should behave similarly (which you have pointed out my experience may be an anomaly, if what you say is correct).

Finally, before you change your gateway's time zone, you should consider the impact that will have on any database connections that are using non-timezone-aware datetime columns, like MS SQL Server. UTC on the gateway and database is a common mitigation for Microsoft's lame JDBC support.

So I think you may misunderstand me. There is nothing in my text that suggest I want to change my gateway timezone.

If you have a moment could you verify that the same scripting from my example works differently for you, or even just verify whether System>CurrentDateTime as shown in your designer shows the time represented as local time or UTC time.

Never said otherwise, again I'm referring to scripts executing through designer's script console as behaving differently than scripts executed through gateway event scripts.

I created a new project under v8.1.20. It defaulted to the Gateway Timezone, which for that VM is UTC. I changed the project setting to "client timezone" and it behaves as expected:

Note that even though it shows Etc/UTC for gateway timezone, the display is still rendered with the designer's timezone.

This has always been true and documented. Designer's scripting console is a variant/extension of Vision Client scope, not gateway scope.

IIRC, if you don't have Vision installed, you don't have the Vision properties pages so cannot set the vision timezone behavior. I believe this is fixed in v8.1.21 (nightlies).

2 Likes

Ah, I think I may have found my issue. Under Project Properties > Vision > General is a setting for Timezone Behavior that was set to 'UTC'. I switched it to Gateway Timezone. This was overlooked as we are not using Vision at all, so I didn't bother with those config settings, but if Designer inherits some properties of the Vision project/client configuration then that makes more sense all around.

After changing that setting and restarting designer behavior appears to match expected.

@pturmel, thanks for sticking with me, despite clearly assuming I was daft. That last little tidbit of knowledge was what I needed.

I'd still contend that it would make sense for the script console to run the same as the gateway context, but I'm sure there are reasons for it being the way it is. If I was doing more Vision scripting I'd probably want it left at Vision context.

1 Like

8.1.22, but yeah, that was a gap in functionality presented since Vision is no longer installed on ~every designer that needs to care about the designer's timezone.

There really is no way to TL;DR the timezone situation in Ignition. The only way to know all the intricacies is to know all the intricacies, unfortunately.

In a perfect world, we'd migrate away from java.util.Date and move to the java.time package everywhere. However, it's a backwards compatibility nightmare, and training folks on the difference between the myriad classes in java.time would also be quite an endeavor.

2 Likes

@PGriffith

Additional suggestions for consideration:

  1. Provide ability to switch/toggle the context of the script console between vision context and gateway context. Defaulting to vision context limits usefulness when you are developing primarily/exclusively for Perspective.
    a. Having the switch/toggle would provide indication of the context that should be expected.
    b. Allowing gateway context from the script console would provide better testing/development strategies for gateway scripting than the implement save and hope (scouring wrapper.log files) workflow the current implementation requires.

  2. With many deployments using perspective exclusively it doesn't make sense to have Designer settings tied to (buried with) Vision settings (even if designer is just a vision client on steroids at heart).

Unrealistic. There are so many resources needed for Perspective script development that are only present in the gateway's classloaders that the designer's script console simply cannot emulate it. Switching just the timezone just papers over the vast differences.

Learn to call gateway message handlers from the designer script console to actually exercise code in gateway scope.

@pturmel Thanks for the suggestion, I will look to get more familiar with message handlers.

As for my suggestion being unrealistic, I'm not convinced. Could be as simple as taking all the script console input text, passing it to the gateway to get parsed and executed on the gateway, and capturing all output and returning that to the script console output window. Seems doable if it were deemed a priority. That doesn't require that the designer emulate the gateway scope at all.

However I'm admittedly less familiar with Ignition's specifics and peculiarities than you, so take my suggestions for what they are... a fresh eyes optimistic opinion of what could be done to improve user experience. I'll leave it for others to prioritize 'em or shoot 'em down.

Hmmm. That sounds do-able. Maybe a 3rd-party module opportunity.

We have plans to do basically that, first-party. No timeline, though.

2 Likes