System.date.now Timezone

When running the function system.date.now() from a perspective session, what time zone should be returned? The user's computer time? Or the server's time?

In Perspective all scripts are run on the gateway so it will return the server's time.

When I go to my Gateway Status page, it shows the time which is in mountain time.

When I run the system.date.now() off a button script in a perspective session, it returns UTC time. Why won't it return the servers time which is in Mountain time?

Where are you seeing the UTC? In your Perspective client?

Go to Project | Project Properties | Perspective General and check what the Project Timezone setting is.

I'm seeing UTC from the perspective client.

The project timezone in the project properties is set to 'Client Timezone'

Hmmm. I'm not sure then. (I'm in Ireland and running on GMT so it's not a problem I have to deal with much.) Someone will be along ...

One last check: When you say "client" do you mean Designer or browser? I suspect they may react differently.

Browser. I tested calling this function running a perspective session via a browser. I'm getting strange behavior when data is inserted into the database (using only system.date.now and system.date.getTimezoneOffset, not any database now functions) from a client in the central timezone.

Our server is in the mountain timezone, I store timestamps in the database in 4 columns: UTC, CST, MST, and EST. I am now getting odd values in the database from users in the central time zone, which we just recently started having users in the central time zone.

The java.util.Date() object returned from any of Ignition's date and time functions, whether expression or script, Has No TimeZone! It is always UTC milliseconds. It is converted to a zoned format when converted to string.

So, if converted to a string in the gateway, it will use the gateway timezone. If in Perspective, in the browser, it will use Perspective's client timezone.

If you convert to string yourself, in a script or expression in Perspective, since those run in the gateway, you will get the gateway's timezone.

2 Likes

MS SQL Server? Its datetime column doesn't play nicely with java.util.Date, and converts to/from a localtime format using the gateway to DB connection properties, which is typically the gateway timezone.

To get reliable Ignition datetime values with MS SQL Server, run both servers in UTC.

1 Like

This is making more sense now. I'm using MySQL but for timestamps, I'm passing all timestamps (UTC, CST, MST, EST) in as parameters.

Below is the function that I'm using to get all 4 timestamps. I use this mostly in gateway scripts but recently started using this function from a Perspective client for data entry to a database.

Basically, I'm getting the UTC offset based on system.date.now, then getting the UTC time from that offset (assuming that the system.date.now() is not in UTC when called). I then assumed that system.date.getTimezone() would change and that's why I have the if statements at the bottom.

def get_timestamps(utc_timestamp=None):
    timezone = system.date.getTimezone()
    utc_offset = system.date.getTimezoneOffset(system.date.now())
    timestamps = {}
    if utc_timestamp is None:
        timestamps["utc_timestamp"] = system.date.addHours(
            system.date.now(), int(abs(utc_offset))
        )
    else:
        timestamps["utc_timestamp"] = utc_timestamp
    mst_offset = 0
    cst_offset = 0
    est_offset = 0
    if timezone == "America/Chicago":
        mst_offset = utc_offset - 1
        cst_offset = utc_offset
        est_offset = utc_offset + 1
    else:
        mst_offset = utc_offset
        cst_offset = utc_offset + 1
        est_offset = utc_offset + 2
    timestamps["mst_timestamp"] = system.date.addHours(
        timestamps["utc_timestamp"], int(mst_offset)
    )
    timestamps["cst_timestamp"] = system.date.addHours(
        timestamps["utc_timestamp"], int(cst_offset)
    )
    timestamps["est_timestamp"] = system.date.addHours(
        timestamps["utc_timestamp"], int(est_offset)
    )
    return timestamps

Don't do that. One instant in time, regardless of zone, is exactly and correctly represented by a java.util.Date object. If you serialize it and send to another machine, it displays in that machine's timezone, but is still the same point in real time.

1 Like

Would it not make sense to get a system.date.nowUtc() instead of using java.util.date? I need a convenient way to use utc dates in my scripts.

But system.date.now() IS UTC. If you need to convert strings to/from UTC everywhere in your gateway, set your gateway timezone to UTC. If you need to use a variety of time zones in gateway scripts (and Perspective scripts), you will need to ask java to render in a specific time zone instead of the gateway timezone. Some techniques:

Let me emphasize what I wrote in an earlier comment: java.util.Date objects are UTC milliseconds under the hood. They already are UTC. Java converts them to strings for display in the JVM's timezone. When a java.util.Date object is serialized and transmitted to a client or designer, it travels as UTC. And then gets stringified in a local time zone wherever the stringification happens.

1 Like

Oh okay! So if IT refuses to put the server in UTC, we will always have time zone based dates in Ignition?

You will always have timezone-based date strings in Ignition. The dates themselves (the objects) have no time zone.

2 Likes

Ok, yes, got it.