Need to calculate the shift number based on a past event datetime tag

I want to assign a value to tag "Shift" based on another daytime tag "Prod_Datetime" from a past event and not the current time. The operator will enter the time to the prod_Datetime tag using a datetime input object. The goal is to autofill the shift value when the event occurred. Get a value of 1 for first shift between 6am and 2 pm. Get a value of 2 for second shift between 2pm and 10 pm. Get a value of 3 for third shift between 10pm and 6 am. I don’t fully understand syntax or scope yet.

Shift tag is Integer
Path [GSI_LabelPrinterControl]Lines/Line 5/LeakerData/Shift

Prod_DateTime is Datetime
Path is [GSI_LabelPrinterControl]Lines/Line 5/LeakerData/Prod_DateTime
Format is yyyy-MM-dd h:mm:ss aa can this be changed to 24hr?

I think suedo code would look something like this

ProdHour = getHour24([GSI_LabelPrinterControl]Lines/Line 5/LeakerData/Prod_DateTime.value)

Shift = [GSI_LabelPrinterControl]Lines/Line 5/LeakerData/Shift.value

if ProdHour >= 06:00:00 and ProdHour < 14:00:00 then Shift = 1

elseif eventTime >= 14:00:00 and eventTime < 22:00:00 then Shift = 2

else Shift = 3

Again, I’m not sure on the syntax here. Not sure where the script would go. Would it be at the shift tag? at the datetime input? There are so many ways this can go and I don't want to start bad habits while learning this platform.

Respectfully,
Anthony

If "Shift" is a global value across the entire gateway, then yes, it's a tag.
Your pseudo code looks like a mix of python and expression. Go straight to expression using the case expression on the shift tag itself.

note: yyyy-MM-dd HH:mm:ss should gave you 24h format

If I understand correctly, you have 2 tags:

  • Prod_DateTime
  • Shift

Prod_DateTime is a memory tag that operator can write to through the interface.
You want Shift to derive its value from Prod_DateTime.

I would make Shift an derived tag, with an expression using case. It would like like one of these:

case (dateExtract({source}, 'hour'),
	6, 1,
	7, 1,
	8, 1,
	9, 1,
	10, 1,
	11, 1,
	12, 1,
	13, 1,
	14, 2,
	15, 2,
	16, 2,
	17, 2,
	18, 2,
	19, 2,
	20, 2,
	21, 2,
	3
)

case (True,
	dateExtract({source}, 'hour') >= 6 || dateExtract({source}, 'hour') < 14, 1,
	dateExtract({source}, 'hour') >= 14 || dateExtract({source}, 'hour') < 22, 2,
	3
)

The second one represents the logic better, but may be slightly harder to read.
I wouldn't worry too much about it re-extracting the hour multiple times. It's not pretty, but the impact should be negligible. I don't think it's worth making an intermediary tag to hold the hours value.

1 Like

Recommended practice in Ignition is to store all timestamps as data type datetime in UTC and not formatted strings. Formatting is done at the last possible point before display for human consumption. This way you can handle timezones, daylight savings, etc. Note that Perspective projects are timezone aware and can (in the Project Properties) be set to display gateway timezone or browser timezone.

2 Likes

I would go so far as to say that this is the only way to store datetimes in any application, otherwise your ability to shift between client timezones goes out the window, as well as working with daylight savings. Datetime strings are extremely fragile

1 Like

I ended up using a submit button under the datetime input with the following code

def runAction(self, event):
	# Get the datetime from the Datetime Input component
	datetime_value = self.getSibling("datetimeInput").props.value  # Replace with actual component name if different
	
	if datetime_value is not None:
	    hour = datetime_value.getHours()  # Java Date object: 0–23
	
	    # Determine shift
	    if 6 <= hour < 14:
	        shift = 1
	    elif 14 <= hour < 22:
	        shift = 2
	    else:
	        shift = 3
	
	    # Write both values to tags
	    system.tag.writeBlocking([
	        "[GSI_LabelPrinterControl]Lines/Bliss Line 5/LeakerData/Prod_DateTime",
	        "[GSI_LabelPrinterControl]Lines/Bliss Line 5/LeakerData/Shift"
	    ], [
	        datetime_value,
	        shift
	    ])
	else:
	    system.perspective.print("No datetime selected")

To get the time I wanted I changed the datetime input.format value from 111 to YYYY-MM-DD HH:mm:ss it was the only way to get the formated value like this 2025-06-02 21:02:00

2 Likes

Be careful of your year formatting.

Make sure, you're using "yyyy" and not "YYYY" in your date format strings. Typically you want to use "yyyy" to represent a four-digit calendar year (e.g. "2021"), while "YYYY" represents a so called 'week year' - see below. Source: Date is displayed with an incorrect year ('yyyy' vs 'YYYY' in date format) – CloverDX Customer Portal

In Expression Language

dateFormat(
	getDate('2024', '11', '30'),
	"yyyy-MMM-dd"
)

returns 2024-Dec-30 - what you are hoping for.

Whereas,

dateFormat(
	getDate('2024', '11', '30'),
	"YYYY-MMM-dd"
)

Returns the week year, 2025-Dec-30 - which may ruin your Christmas holidays. Week 1 this year started on 2024-12-30.

Jython will also give the same results. Try this in the Script Console:

d = system.date.getDate(2024, 11, 31)
system.date.format(d, "YYYY-MMM-DD")
system.date.format(d, "yyyy-MMM-DD")

e = system.date.getDate(2024, 11, 31)
system.date.format(e, "YYYY-MMM-dd")
system.date.format(e, "yyyy-MMM-dd")

Result:

u'2025-Dec-366'
u'2024-Dec-366'
u'2025-Dec-31'
u'2024-Dec-31'
>>>

See the Java docs for more:

datetime_value = self.getSibling("datetimeInput").props.value

On a separate note, you can avoid all the getSibling / Parent / Uncle / Nephew syntax as follows:

  • Create a custom property, dateTimeInput on the view.
  • Create a binding from the DateTime input component's value property to view.custom.dateTimeInput. Make it bidirectional.
  • Modify your scripts or bindings to use view.custom.dateTimeInput.

Now your application won't break if you rename something or move it in or out of a container.
You'll also be able to examine all the values at once in the view property's CUSTOM section.

2 Likes

If you are using my Integration Toolkit, you can use transform() to capture the hour in one spot. Makes the whole thing easier to read, too.

2 Likes

Thanks for explainging the YYYY vs yyyy. If I use yyyy then the format result breaks, Using YYYY the format result is as desired.
For example Using YYYY

Using yyyy How do I resolve the resulting format error?

I would also love to do it without the submit button but I think I'm binding wrong or something. I have the datetimeinput.value bidirectionally tied to my prod_datetime tag. (which is also a datetime tag as suggested earlier. This tag is not a "now" timestamp but a chosen time in history.

I can't tell you all how grateful I am for the support.

Just to bring the joy of learning to your heart, Perspective - DateTime Input | Ignition User Manual says,

format
Template for formatting date display - must be valid moment.js format, e.g., 'MM/DD/YYYY h:mm a'.

Their docs are at https://momentjs.com/. If you find a good formatting summary perhaps you could post a link here.

I suspect that this formatting is done in the browser rather than on the gateway, hence the Javascript formatting rather than the Java. We don't really have time for this, do we?

I played around with the DateTime Input component to reproduce your problem. I saw it for a moment and then, whatever I typed, it fixed itself and I can't reproduce it. That could be a problem in Designer which has to do a pile of trickery to work like a browser. Test in a real browser.

1 Like

Ok, this may be a dumb question but what do you mean by test in a browser vs designer? can you design in a browser? or do you mean run the live view from a browser? I did run the browser and I get the same error.

So I think I have a solution When you initially bring in a Datetiminput compenent, the format is "111"

So I make my target tag a 24 format instead of the Datetiminput

For some reason, I didnt think to use the Datetime component for my action, but it DOES have an action so, I move my on action script from the button to the Datetimeinput and tested.

Sure enough the onaction script in the Datetimeinput works and the shift is updated when you pic a time.

On a side note, once you change the Datetimeinput format from "111" you cant change it bock so I had to pull another one.

In the End the system works as needed and the only format change was in the target tag. I have some other issues, but I will start a new thread for those. Thanks everyone and have a good day

Tha's lll (lower case L), not 111 (the digit)

2 Likes

I can't help feeling that you're doing something wrong here using a tag to hold the shift number for a historical date. The only reason I can think of is that if one user changes the date then all users should see it.

If you're using it as a global variable then use SESSION CUSTOM properties, available by selecting Perspective in Project Browser and scrolling down to the bottom in the Perspective Property Editor. Doing this will isolate each session so that users don't interfere with each other.

1 Like

To be honest, I am probably doing a lot of things wrong here. While I am well versed in Proficy, and can get by in Wonderware, I am very new to how ignition works. I almost sent the data to a different system to process it there and just reference tags in the ignition prospective view, but that wouldn't be any fun would it? I want to learn it and my client is paying me to figure it out. I am very grateful to the support and people here. Anyway, to explain a little better there is a paper form that is used to describe details of a product that leaks. The tag Shift is for the report. It will represent when the defect occurred and is used to easily categorize the Db table by shift. It is one of many tags specifically requested to be on the form and written to the Db. I must iterate again, "me noob" lol. I got the request, and the client got ignition, so I'm getting the job done and improving as I progress, I will realize I am not very efficient at this point and will improve as I learn. Again, Thank you all for the learning experience.

Respectfully,
Anthony

Yes, no need for a tag there. The date can be input using a datepicker with its value bound to a custom property on the view. (Make the binding bidirectional so the datepicker can write to it and not just read.)
Do the same with all the other form values.
The action or script that writes to the database then just takes all those custom props as parameters.

It might help to set up the custom property as an object with a structure like,

CUSTOM
reportRecordData
  + date : 2025-06-05 14:02
  + shift: 2
  + product : Product that should not leak
  + pass: true

Now you can easily use these. Clients on multiple machines won't interfere with each other (which they will with your tag approach).

If you're not already, use Named Queries | Ignition User Manual, Watch the video!

1 Like

Not sure if it is proper forum etiquette to chat here as this seems to be the start of a tangent I want to engage in. Is it acceptable to continue in this post or is there a chat area or some other means to continue? Is there an IRC or something for the forums?

Create a thread in the General Discussion section. I won't be available for the rest of the day but others will chip in.

1 Like