# Gateway Timezones and Script function behavior

**URL:** <https://forum.inductiveautomation.com/t/gateway-timezones-and-script-function-behavior/107050>\
**Category:** Ignition\
**Tags:** scripting, perspective\
**Created:** [June 4, 2025, 7:55pm UTC](https://forum.inductiveautomation.com/t/gateway-timezones-and-script-function-behavior/107050 "2025-06-04T19:55:53Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![benjamin.nothwehr](https://avatars.discourse-cdn.com/v4/letter/b/ea666f/32.png) [@benjamin.nothwehr](https://forum.inductiveautomation.com/u/benjamin.nothwehr)\
**Post date:** [June 4, 2025, 7:55pm UTC](https://forum.inductiveautomation.com/t/gateway-timezones-and-script-function-behavior/107050/1 "2025-06-04T19:55:54Z")

</div>

Hello, I have some questions about time functions and timezones. We are using Ignition version 8.1.37 and MES OEE Downtime 3.81.10.

We have our frontend and backend gateways located in the UK. They are serving a packaging line in US/Central, and will also serve equipment in other timezones eventually. I'm trying to understand how some of the functions work with regard to timezones and display of time data from the MES database using the MESAnalysisController component.

Here is a screenshot of a perspective dashboard with the results of various functions and session properties (in US/Central):

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/4/6/465569f420b799096b3a2ce811e2f810903d42b7.png)

Here is the same dashboard (in Europe/London):

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/9/4/945d00d0d1679a33025e1e0efb6dbf94c9a5946d.png)

Project\>properties\>Designer = Gateway Timezone  
Project\>properties\>General = Client Timezone

Questions:

1. Why does the getTimezone() function always yield "Europe/London"?
2. Why does midnight() function give me midnight for the gateway server and not the client?
3. All of the MES data is timestamped UTC in the database, but I want the dashboard to display data based on central time (for example - charts for today's OEE statistics and downtime reasons should show today in US/Central regardless of where I pull them up). How can I use timezone functions to do this without hard coding -6 (current UTC offset from London)? -Especially since the daylight savings does not always match up, and may change in the future.  
Thanks!  
Ben

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [June 4, 2025, 8:32pm UTC](https://forum.inductiveautomation.com/t/gateway-timezones-and-script-function-behavior/107050/2 "2025-06-04T20:32:46Z")

</div>

1. Because the expression runs in the gateway, not in the client.

2. Because the expression runs in the gateway, not in the client.

3. You will need to set the project timezone to "America/Chicago" so Perspective components that understand date/time types can handle them in your desired timezone, and use scripts to apply `session.props.timeZoneId` wherever you wish direct control over datetime formatting.

See this topic for suggestions on the latter (read the whole topic):

> [@Ignition Perspective Page to show the client System date and time](https://forum.inductiveautomation.com/t/ignition-perspective-page-to-show-the-client-system-date-and-time/73265):
>
> Is it possible to display the client computer/system date and time on perspective web page? dateFormat(now(60000), "yyyy-MMM-dd HH:mm:ss a") showing the Gateway Server system date and time. Under Browse Tags-\> System -\> Client Tags are not available for Perspective sessions.

---

<div class="post-metadata">

**Author:** ![benjamin.nothwehr](https://avatars.discourse-cdn.com/v4/letter/b/ea666f/32.png) [@benjamin.nothwehr](https://forum.inductiveautomation.com/u/benjamin.nothwehr)\
**Post date:** [June 5, 2025, 1:31pm UTC](https://forum.inductiveautomation.com/t/gateway-timezones-and-script-function-behavior/107050/3 "2025-06-05T13:31:25Z")

</div>

Ok thank you - this is helpful, but I think what I really need is the ability for a given day/datetime to find the Offset between "Europe/London" and "US/Central." Any suggestions for that?

Here is the code I currently use to set the startDate and endDate for the MESAnalysisController to perform an iterative query of the OEE for the last 14 days for a dashboard. The Custom property is an integer called "custom.DayCount.set" that increments for each day and gets set to -1 when finished.

The 6 hour offset set in the line for self.props.startDate works fine now and will in the winter, but when daylight savings doesn't match up, there will be a slight issue. Plus, when this is propogated to other sites, I want this calculation to work for other timezones.

```python
def valueChanged(self, previousValue, currentValue, origin, missedEvents):
	
	
	if currentValue.value > -1 and currentValue.value < 16:
			CurrentDay = currentValue.value - 14
			
			self.props.startDate = system.date.addHours(system.date.addDays(system.date.midnight(system.date.now()),CurrentDay),6)
			self.props.endDate = system.date.addDays(self.props.startDate, 1)

	else:
		if currentValue.value == -1:
			self.custom.DayCount.ret = -1

```

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [June 5, 2025, 1:52pm UTC](https://forum.inductiveautomation.com/t/gateway-timezones-and-script-function-behavior/107050/4 "2025-06-05T13:52:39Z")

</div>

> [@benjamin.nothwehr](#):
>
> I think what I really need

**NO**

Don't do arithmetic with dates to correct for time zones. `java.util.Date` objects are fundamentally UTC under the hood, representing a worldwide point in time, and trying to "adjust" them to correct for timezones simply makes them **incorrect**. If you pass incorrect timestamps to historian calls or other system functions, you will get **wrong answers**.

These objects are stringified in the timezone of the JVM that does the string conversion, and are created by string parsing in the timezone of the JVM that does the parsing.

If you want to stringify or parse in a timezone other than the JVM's timezone, you **must** use the zone-aware java data types.

---

<div class="post-metadata">

**Author:** ![benjamin.nothwehr](https://avatars.discourse-cdn.com/v4/letter/b/ea666f/32.png) [@benjamin.nothwehr](https://forum.inductiveautomation.com/u/benjamin.nothwehr)\
**Post date:** [June 5, 2025, 2:18pm UTC](https://forum.inductiveautomation.com/t/gateway-timezones-and-script-function-behavior/107050/5 "2025-06-05T14:18:01Z")

</div>

Ok, thank you for your response. How should I go about iteratively producing the timestamp for midnight to midnight central time? (Keep in mind, I don't have the ability to directly query the MES database and must use the MESAnalysisController, which has pre-canned queries that I can only feed timestamps to.)

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [June 5, 2025, 7:46pm UTC](https://forum.inductiveautomation.com/t/gateway-timezones-and-script-function-behavior/107050/6 "2025-06-05T19:46:19Z")

</div>

I would use something like:

```python
from java.util import Date
from java.time import ZoneId, ZonedDateTime

def getChicagoMidnight():
	ts0 = ZonedDateTime.now(ZoneId.of("America/Chicago"))
	midnight = ZonedDateTime.of(ts0.year, ts0.monthValue, ts0.day, 0, 0, 0, 0, ts0.zone)
	return Date.from(midnight.toInstant())

```

---

<div class="post-metadata">

**Author:** ![benjamin.nothwehr](https://avatars.discourse-cdn.com/v4/letter/b/ea666f/32.png) [@benjamin.nothwehr](https://forum.inductiveautomation.com/u/benjamin.nothwehr)\
**Post date:** [June 5, 2025, 10:35pm UTC](https://forum.inductiveautomation.com/t/gateway-timezones-and-script-function-behavior/107050/7 "2025-06-05T22:35:29Z")

</div>

Ok great - thank you! I ended up modifying it - please let me know if I'm doing anything foolish:

```python
from java.time import ZonedDateTime
from java.time import ZoneId
from java.util import Date

def getChicagoMidnight(x):
    """
    Returns the midnight time for 'x' days ago in the Chicago timezone.

    :param x: Number of days from today (negative integer).
    :return: ZonedDateTime representing midnight of that day.
    """
    # Define the Chicago timezone
    chicago_zone = ZoneId.of("America/Chicago")
    
    # Get the current date-time in Chicago timezone
    now = ZonedDateTime.now(chicago_zone)
    
    # Calculate the date for 'x' days ago where x is a negative number indicating days ago
    date_x_days_ago = now.plusDays(x).toLocalDate()
    
    # Create a ZonedDateTime for midnight of that date
    midnight = ZonedDateTime.of(date_x_days_ago.getYear(),date_x_days_ago.getMonthValue(),date_x_days_ago.getDayOfMonth(), 0, 0, 0, 0,chicago_zone)
 
    # Convert ZonedDateTime to java.util.Date
    midnight_date = Date.from(midnight.toInstant())
        
    return midnight_date

```

And I call it in the change script on my day counter:

```python
def valueChanged(self, previousValue, currentValue, origin, missedEvents):
	from java.util import Calendar, TimeZone
	from java.text import SimpleDateFormat
	

	
	
	
	if currentValue.value > -1 and currentValue.value < 16:
			CurrentDay = currentValue.value - 14
			
			self.props.startDate = timeStampMaker.getChicagoMidnight(CurrentDay)
			self.props.endDate = timeStampMaker.getChicagoMidnight(CurrentDay+1)

			

	else:
		if currentValue.value == -1:
			self.custom.DayCount.ret = -1

```

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [June 5, 2025, 11:50pm UTC](https://forum.inductiveautomation.com/t/gateway-timezones-and-script-function-behavior/107050/8 "2025-06-05T23:50:48Z")

</div>

I would drop the .toLocalDate(). Unnecessary and potentially confusing.

Consider computing both start and end date from a single call to `ZonedDateTime.now()`. There's a tiny race worth avoiding.

---

<div class="post-metadata">

**Author:** ![michael.flagler](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/michael.flagler/32/26272_2.png) [@michael.flagler](https://forum.inductiveautomation.com/u/michael.flagler)\
**Post date:** [June 5, 2025, 11:57pm UTC](https://forum.inductiveautomation.com/t/gateway-timezones-and-script-function-behavior/107050/9 "2025-06-05T23:57:01Z")

</div>

Couldn't you just get the startDate then just add 1 day to that date to avoid the race?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [June 5, 2025, 11:58pm UTC](https://forum.inductiveautomation.com/t/gateway-timezones-and-script-function-behavior/107050/10 "2025-06-05T23:58:45Z")

</div>

No, you want to do the date arithmetic with the ZonedDateTime so that it crosses daylight time changes properly (in the desired zone, not the gateway zone). I'd compute midnight once (separate function, perhaps), then do arithmetic and conversion to `Date` for each endpoint.
