# Which is Better Gateway Schedule or Gateway Timer script

**URL:** <https://forum.inductiveautomation.com/t/which-is-better-gateway-schedule-or-gateway-timer-script/75073>\
**Category:** Ignition\
**Tags:** perspective\
**Created:** [June 15, 2023, 12:22pm UTC](https://forum.inductiveautomation.com/t/which-is-better-gateway-schedule-or-gateway-timer-script/75073 "2023-06-15T12:22:17Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Sourabh\_Ambildhuke](https://avatars.discourse-cdn.com/v4/letter/s/f1d935/32.png) [@Sourabh\_Ambildhuke](https://forum.inductiveautomation.com/u/Sourabh_Ambildhuke)\
**Post date:** [June 15, 2023, 12:22pm UTC](https://forum.inductiveautomation.com/t/which-is-better-gateway-schedule-or-gateway-timer-script/75073/1 "2023-06-15T12:22:17Z")

</div>

Hi team,

I just want suggestion on Gateway Events script. The requirement is I have 2 scripts which are running when day starts and other 2 runs throughout the day so which gateway script we need to use for server optimum performance.

---

<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 15, 2023, 12:29pm UTC](https://forum.inductiveautomation.com/t/which-is-better-gateway-schedule-or-gateway-timer-script/75073/2 "2023-06-15T12:29:29Z")

</div>

The ones that need to run at specific times should use the scheduled event. Because you can specify the time of day for it to run.

The choice for the others depends on how fast you need them to run, and if they should be aligned to the clock. The timer event just runs at a pace. Either with a fixed interval from start-to-start, or a fixed pause from finish-to-start. These can be set to run very often--fractions of a second apart. The scheduled event cannot run so often, but can be aligned to run close to even intervals on the clock, like right after the top of each hour. Or every quarter hour on the quarter hour (minute==0,15,30,45).

---

<div class="post-metadata">

**Author:** ![Sourabh\_Ambildhuke](https://avatars.discourse-cdn.com/v4/letter/s/f1d935/32.png) [@Sourabh\_Ambildhuke](https://forum.inductiveautomation.com/u/Sourabh_Ambildhuke)\
**Post date:** [June 15, 2023, 12:57pm UTC](https://forum.inductiveautomation.com/t/which-is-better-gateway-schedule-or-gateway-timer-script/75073/3 "2023-06-15T12:57:25Z")

</div>

Thanks for the detail difference.

Why i asked is we are facing major issue with timer script which has delay of 2500 sec but it is still taking 400sec to execute script which in turn make the application slow. so do you have anything for this. Please find image as script is slow.

 ![MicrosoftTeams-image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/d/5/d52dda62de75fc5209464aeb8d9e2a2bccbe6a9c.png)

---

<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 15, 2023, 1:01pm UTC](https://forum.inductiveautomation.com/t/which-is-better-gateway-schedule-or-gateway-timer-script/75073/4 "2023-06-15T13:01:26Z")

</div>

> [@Sourabh\_Ambildhuke](#):
>
> but it is still taking 400sec

That is entirely the fault of the code you are trying to run. There's no magic wand to make the code run faster. But if you share your code, we might be able to help you clean it up (optimize it).

Sometimes code is simple but takes a long time for other reasons, like a slow database, or a huge amount of data on which to perform calculations. We might be able to help optimize your database, but we'd need more info.

{ It is hard to tell in your graphic, but are those commas in your rate column? }

---

<div class="post-metadata">

**Author:** ![Sourabh\_Ambildhuke](https://avatars.discourse-cdn.com/v4/letter/s/f1d935/32.png) [@Sourabh\_Ambildhuke](https://forum.inductiveautomation.com/u/Sourabh_Ambildhuke)\
**Post date:** [June 15, 2023, 1:26pm UTC](https://forum.inductiveautomation.com/t/which-is-better-gateway-schedule-or-gateway-timer-script/75073/5 "2023-06-15T13:26:42Z")

</div>

> [@pturmel](#):
>
> { It is hard to tell in your graphic, but are those commas in your rate column? }

it is comma, please suggest me for better time. I have attached script for which we are facing issue.  
UpdateOEEtag script which will call function in historiandata function. Please check and let me know  
[MDT\_OEE\_App\_V2\_2023-06-14\_histDat.zip](https://forum.inductiveautomation.com/uploads/short-url/pExjte0qX5VnYesSzzkMmnndzXw.zip) (20.6 KB)  
[UpdateOEETag\_Script\_2023-06-13.zip](https://forum.inductiveautomation.com/uploads/short-url/cneQcms8856pUs15lvTYYGu5r0L.zip) (5.6 KB)

---

<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 15, 2023, 1:33pm UTC](https://forum.inductiveautomation.com/t/which-is-better-gateway-schedule-or-gateway-timer-script/75073/6 "2023-06-15T13:33:18Z")

</div>

Whoa! Those are a bit large to ask this volunteer to review.

---

<div class="post-metadata">

**Author:** ![Sourabh\_Ambildhuke](https://avatars.discourse-cdn.com/v4/letter/s/f1d935/32.png) [@Sourabh\_Ambildhuke](https://forum.inductiveautomation.com/u/Sourabh_Ambildhuke)\
**Post date:** [June 15, 2023, 2:27pm UTC](https://forum.inductiveautomation.com/t/which-is-better-gateway-schedule-or-gateway-timer-script/75073/7 "2023-06-15T14:27:09Z")

</div>

Sorry @pturmel what can i do for you to make it shorter

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [June 15, 2023, 2:36pm UTC](https://forum.inductiveautomation.com/t/which-is-better-gateway-schedule-or-gateway-timer-script/75073/8 "2023-06-15T14:36:49Z")

</div>

Wait, what exactly are you running in your event scripts ? Not the whole thing I hope ?

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [June 15, 2023, 2:44pm UTC](https://forum.inductiveautomation.com/t/which-is-better-gateway-schedule-or-gateway-timer-script/75073/9 "2023-06-15T14:44:51Z")

</div>

I only looked at UpdateOEETag\_Script here is what I see.

Don't do this:

```python
sys.exit()

```

> [@Question about Exit()](https://forum.inductiveautomation.com/t/question-about-exit/74731/4):
>
> sys.exit() and the Java equivalent aren't designed to return early from a method, they're designed to end the execution of the program, and the only reason your Ignition Gateway / JVM doesn't cease to exist after that is because we've hooked into prevent it. It's not meant for what you're using it for.

You can unpack pyDataSets so your for loop can be written as:

```python
for machineName,zoneName,lineId,facilityName,attachedTo in allShifts:

```

If you do that, then there is no need for the if statement prior to the loop, if allShifts is empty, it just wont run. So remove:

```auto
if(len(allShifts) > 0):

```

What is the point of the `try: except:` block in the for loop if you're not going to log an issue? Also, I really don't think that you need it here, but since you're calling external functions perhaps you do?

This:

```python
if (len(result) > 0):

```

Should be written as

```python
if result:

```

You've already set count to 0 so there is not need for the else in this if statement, but meh...

I don't know what you're doing in the `HistorianData` functions but you are calling `getOeewithZone()` and `getUnattendedDT()` multiple times, perhaps seeing the code for those functions we could provide some more insight.

I would certainly combine all of your tag writes into a single function call, and remove the unneeded string conversions.

Something like:

```auto
tags = ['OEE','Availablity','Downtime','GoodCount','Performance','Quality','Runtime','Scrap','UnattendedDT','IsHoliday','Department']
tagPaths = ['{0}{1}/{2}/{3}'.format(machineOEEPath,facilityName,machineName,tag) for tag in tags]
tagValues = [oee,availability,totalDownTime,goodCount,performance,quality,runTime,scrapCount,count,Holiday,attachedTo]
system.tag.writeAsync(tagPaths,tagValues)

```

You're collecting error info to log, but then not actually logging it in you're final except block.

There is also potentially a typo in one of your tag paths. You have `'UnattendentDT'` but I think you might mean `'UnattendedDT'`?

---

<div class="post-metadata">

**Author:** ![Sourabh\_Ambildhuke](https://avatars.discourse-cdn.com/v4/letter/s/f1d935/32.png) [@Sourabh\_Ambildhuke](https://forum.inductiveautomation.com/u/Sourabh_Ambildhuke)\
**Post date:** [June 15, 2023, 6:23pm UTC](https://forum.inductiveautomation.com/t/which-is-better-gateway-schedule-or-gateway-timer-script/75073/10 "2023-06-15T18:23:00Z")

</div>

Thanks @lrose I have worked with script with changes you mentioned. I have getoeewithzone can you help me with that.

```auto
def getOeewithZone(stTime,enTime,Facility,Line,lineValue,IsMonthToDate,zoneName,isExist = 0,decimalValue = 0,shift = 1):
    try:
        totalCount = 0
        goodCount = 0
        isFullTimeDown = False
        totalDowntimeMin = 0
        shiftEndTime = enTime
        zoneEndTime = enTime
        if(isExist == 1):
            enTime = str(system.date.format(system.date.now(),"yyyy-MM-dd HH:mm:00"))
        isQuality = system.tag.read(str(configurationTagPath) + str(Facility) + '/' + str(Line) + '/Is_Quality_Visible').value
        isPerformance = system.tag.read(str(configurationTagPath) + str(Facility) + '/' + str(Line) + '/Is_Performance_Visible').value
        tag = ''
        scrapTagPath = str(configurationTagPath)+str(Facility)+'/'+str(Line)+'/Is_Manual_Scrap'
        isManualScap = system.tag.read(scrapTagPath).value
        startTimeUTC = getUTCfromTimeZone(zoneName, system.date.parse(stTime), -1)
        endTimeUTC = enTime
        if(isExist == 0):
            endTimeUTC = getUTCfromTimeZone(zoneName, system.date.parse(enTime), -1)

        runTime,downTime,downTimeRangeTable,targetUnit,plannedDownTime = getOeeCalculationValues(startTimeUTC , endTimeUTC, Facility ,Line,lineValue,decimalValue)
        totalCount = getOEEProdCount(startTimeUTC, endTimeUTC, Facility ,Line)

        #endTimeUTC1 = getUTCfromTimeZone(zoneName, system.date.parse(enTime), +1)
        hourStartTime = str(system.date.format(system.date.parse(stTime),"yyyy-MM-dd HH:mm:00"))
        hourEndTime = str(system.date.format(system.date.parse(enTime),"yyyy-MM-dd HH:mm:00"))
        #----

 

        if(int(isManualScap)==1):
            paramsScrap = {"LineId":lineValue,"HourStart":hourStartTime,"HourEnd":shiftEndTime,"IsMonthToDate":shift} #changed to include currentHour scrap quantity
            scrapCount = system.db.runNamedQuery("Project_OEE/Scrap/Get_OEE_Total_Scrap_Count",paramsScrap)
        else:
            scrapCount = getPlcScrapCount(startTimeUTC,endTimeUTC,Facility ,Line)
            totalCount = totalCount + scrapCount

        #This function is used to fetch total break duration of configured breaks in minutes
        Bktime = getShiftBreaktime(shift ,lineValue, zoneName)

        totalTime = system.date.minutesBetween(system.date.parse(startTimeUTC),system.date.parse(endTimeUTC))

 

        stTime = system.date.parse(stTime)
        zoneEndTime = system.date.parse(zoneEndTime)
# system.perspective.print('!!@@@@stTime...'+str(stTime))    
# system.perspective.print('!!@@@@zoneEndTime...'+str(zoneEndTime))    
        # to get downtime duration data from Holiday Table
        isFullTimeDown, totalDowntimeMin = getDowntimeConfigurationTime(stTime, zoneEndTime, lineValue)

        if (isFullTimeDown):
            totalTime = 0
        else:
            totalTime = totalTime - plannedDownTime - Bktime - totalDowntimeMin

 

        if(int(runTime) == 0):
            Efficiency = 0
        else:    
            if(int(totalTime) > 0):
                Efficiency = float(runTime) / float(totalTime)
            else:
                Efficiency = 0    
        #system.perspective.print("@@runTime : "+ str(runTime))
        #system.perspective.print("@@Efficiency : "+ str(Efficiency))
        if(str(isPerformance) == 'None'):
            isPerformance = 0
        if(int(isPerformance) == 0):
            Performance = 1
        else:
            if(int(runTime) == 0):
                Performance = 0    
            else:
                if(targetUnit != 0):
                    #Performance = float(goodCount) / float(targetUnit) #Change 18thjuly
                    Performance = float(totalCount) / float(targetUnit)
                else:
                    Performance = 0    
        #system.perspective.print("@@Performance : "+ str(Performance))
        if(str(isQuality) == 'None'):
            isQuality = 0
        if(int(isQuality) == 0):        
            Quality = 1
        else:    
            if((int(totalCount) == 0) and (int(scrapCount) == 0)):    
                    Quality = 0        
            else:
    # Quality = float(goodCount)/float((goodCount + scrapCount))
                goodCount= totalCount-scrapCount    
                Quality = float(goodCount)/float(totalCount) #Change for MI Site

        oee = round((Efficiency*Performance*Quality*100) ,int(decimalValue))
        avilability = round((Efficiency*100) , int(decimalValue))
        performance = round((Performance*100) , int(decimalValue))
        quality = round((Quality*100) , int(decimalValue))
        totalRunTime = round((float(runTime) / float(60)) , int(decimalValue))    
    # system.perspective.print('@@@avilability'+str(avilability))
        totalDownTime = round((float(downTime) / float(60)),int(decimalValue))
        goodCount = goodCount
        targetUnit = round(targetUnit,int(decimalValue))

        return oee,avilability,performance,quality,totalRunTime,totalDownTime,goodCount,targetUnit,runTime,downTime,downTimeRangeTable,scrapCount,totalTime,isFullTimeDown
    except:
        exc_type, exc_obj,tb = sys.exc_info()
        lineno = tb.tb_lineno
        errorMessage = "Error , Line:" + str(lineno) + ", Err:"+ str(exc_obj)    
        #system.perspective.print(errorMessage)
        ErrorLogs.addLogDetails('script','HistorianData','getOeewithZone',2,lineno, str(exc_obj))

```

```auto
def getUnattendedDT(facility,lineValue,line,currentTime,startTime,endTime,shift,startHour,endHour,day,zoneName,batchId):
    try:
        parentStartHour = startHour #Considering this is start hour of shift selected in HH format
        parentEndHour = endHour #Considering this is end hour of shift selected in HH format
        parentStartTime = system.date.format(startTime , "yyyy-MM-dd")
        parentEndTime = system.date.format(endTime , "yyyy-MM-dd")

        #now find the number of hours of shift by sustracting start time from end time.
        totalHours = system.date.hoursBetween(startTime,endTime)
        diffMinutes = int(system.date.format(startTime,'mm')) - int(system.date.format(endTime,'mm'))
        if(diffMinutes != 0):
            totalHours = totalHours + 1
        data = []
        partNumber = ''
        isCurrentHour = 0
        lastPartNumber = '-1'
        startTimeUTC = ShiftTimeZone.getUTCfromTimeZone(zoneName, startTime, -1)
        endTimeUTC = ShiftTimeZone.getUTCfromTimeZone(zoneName, endTime, -1)

        partNumberDetails = getPartNumberwithZone(startTimeUTC , endTimeUTC, facility ,line, zoneName)

        hourCount = 1
        runTimetable,downTimetable,plannedDowntimeTable,finaldownTimeLapsed = getTotalEquipCalculation(system.date.format(startTimeUTC, 'yyyy-MM-dd HH:mm:ss'),system.date.format(currentTime, 'yyyy-MM-dd HH:mm:ss'),facility,line,int(1))
        downTimetable = system.dataset.toPyDataSet(downTimetable)
        plannedDowntimeTable = system.dataset.toPyDataSet(plannedDowntimeTable)
# system.perspective.print("LineNo 2334")
# params = {'LineId':lineValue, 'Day':day, 'HourStart':startTime, 'HourEnd':endTime}
# plannedDowntimeTable = system.db.runNamedQuery('Project_OEE/Hourly/DownTime/Get_PlannedDownTimeDetails_ByRange', params)
# plannedDowntimeTable = plannedDownTimetable plannedDowntimeTable
# system.perspective.print("LineNo 2339")
        params = {"LineId":int(lineValue)}
        downtimesDt = system.db.runNamedQuery("Project_OEE/Hourly/DownTime/Get_AllDownTimeCode")
        dtDescdataset = system.dataset.toPyDataSet(downtimesDt)
# system.perspective.print("LineNo 2343")
        dtTagPath = str(configurationTagPath)+str(facility)+'/'+str(facility)+'/DT_sec'    
# system.perspective.print("LineNo 2353 "+str(dtTagPath))
        DT_Sec = system.tag.read(dtTagPath).value

        for rowIndex in range(totalHours):
            sTime = system.date.addHours(startTime,rowIndex)
            sTime = system.date.setTime(sTime,system.date.getHour24(sTime),system.date.getMinute(sTime),00)
            sTime = system.date.format(sTime , "yyyy-MM-dd HH:mm:ss")
            enTime = system.date.addHours(startTime,rowIndex+1)
            enTime = system.date.setTime(enTime,system.date.getHour24(enTime),system.date.getMinute(enTime),00)
            enTime= system.date.format(enTime , "yyyy-MM-dd HH:mm:ss")
            sTimeHour = system.date.format(system.date.parse(sTime),"HH")    
            enTimeHour = system.date.format(system.date.parse(enTime),"HH")

 

            if (rowIndex == (totalHours - 1)):
                if (system.date.parse(enTime) > endTime):
                    enTime= system.date.format(endTime , "yyyy-MM-dd HH:mm:ss")

 

            if(isCurrentHour == 0):

                #isCurrentShift = system.date.isBetween(system.date.now(), system.date.parse(startTime), system.date.parse(endTime))
                isCurrentShift = system.date.isBetween(currentTime, system.date.parse(startTimeUTC), system.date.parse(endTimeUTC))
                isCurrentShiftHour = fullTimeComparewithZone(system.date.format(system.date.parse(sTime),'HH:mm'), system.date.format(system.date.parse(enTime), 'HH:mm'),zoneName)
                if(int(isCurrentShiftHour) == 1 and int(isCurrentShift) == 1):
                    isCurrentHour = 1
                partNumberData = getHourPartNumber(sTime,enTime,partNumberDetails)

                for rowPartNumber in range(len(partNumberData)):
                    partStartTime = partNumberData[rowPartNumber][0]
                    partEndTime = partNumberData[rowPartNumber][1]
                    partNumber = partNumberData[rowPartNumber][2]

                #--------------Added to get correct hour for hours with partnumber changed (splitted hours)
                    if lastPartNumber != '-1':
                        if lastPartNumber != partNumber:
                            hourCount = hourCount + 1
                    lastPartNumber = partNumber
                #-------------- change end (by Abhijit)

                    partStartTimeUTC = ShiftTimeZone.getUTCfromTimeZone(zoneName, system.date.parse(partStartTime), -1)
                    partEndTimeUTC = ShiftTimeZone.getUTCfromTimeZone(zoneName, system.date.parse(partEndTime), -1)
# system.perspective.print("LineNo 2373")
                    runTime, downTime, downTimeRangeTable, plannedTotalTime,plannedDownTimeRangeTable = getHourDowntime(partStartTimeUTC,partEndTimeUTC,downTimetable,plannedDowntimeTable,currentTime,isCurrentHour,int(1))
# system.perspective.print("LineNo 2374")
                    for downDT in range(len(downTimeRangeTable)):
                        startT = downTimeRangeTable[downDT][0]
                        endT = downTimeRangeTable[downDT][1]
                        descDT = downTimeRangeTable[downDT][2]
                        levelDT = 'Level1'
                        if(levelDT == 'Level1'):
                            diffSec = system.date.secondsBetween(system.date.parse(startT), system.date.parse(endT))
                            if(diffSec >= int(DT_Sec)):
# if(diffSec >= 120):
                                if(zoneName != '' and startT != ''):
                                    startT = ShiftTimeZone.getUTCfromTimeZone(zoneName, system.date.parse(startT), 1)
                                    startT = system.date.parse(startT)
                                if(zoneName != '' and endT != ''):
                                    endT = ShiftTimeZone.getUTCfromTimeZone(zoneName, system.date.parse(endT), 1)
                                    endT = system.date.parse(endT)
                                #add logic here to check if the Downtime is attended
                                params = {"BatchId": batchId,"DownTimeStart":startT,"DownTimeEnd":endT}
# system.perspective.print("!!!downtimeData: "+str(params))    
                                DowntimeData = system.db.runNamedQuery("Project_OEE/Hourly/DownTime/Get_DowntimeByBatchIdStartDate", params)
                                DowntimeData = system.dataset.toPyDataSet(DowntimeData)
                                if(len(DowntimeData) < 1):
                                    if(len(dtDescdataset)>0):
                                        for f in range(len(dtDescdataset)):
                                            if(int(descDT) == int(dtDescdataset[f][0])):
                                                descDT = dtDescdataset[f][1]
                                                break
                                    data.append([round(diffSec/60.0,1),descDT,system.date.format(startT,'yyyy-MM-dd HH:mm:ss'),system.date.format(endT,'yyyy-MM-dd HH:mm:ss'),hourCount])
                hourCount = hourCount + 1
        header = ['Actual','Description','Start time','End time','HourCount']
        dataFinal = system.dataset.toDataSet(header, data)
        dataFinal = system.dataset.toPyDataSet(dataFinal)
        return dataFinal
    except:
        exc_type, exc_obj,tb = sys.exc_info()
        f = tb.tb_frame
        lineno = tb.tb_lineno
        errorMessage = "Line Number:" + str(lineno) + ", Err:"+ str(exc_obj)+' '+str(line)
        #system.perspective.print("!!Error getUnattendedDT: "+str(errorMessage))
        ErrorLogs.addLogDetails('script','getUnattendedDT','getUnattendedDT',2,lineno,errorMessage)

```

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [June 15, 2023, 7:48pm UTC](https://forum.inductiveautomation.com/t/which-is-better-gateway-schedule-or-gateway-timer-script/75073/11 "2023-06-15T19:48:17Z")

</div>

If you're going to use boolean flags you should use the boolean built ins, so the function signature should be:

```auto
def getOeewithZone(stTime,enTime,Facility,Line,lineValue,IsMonthToDate,zoneName,isExist = False, decimalValue = False, shift = True):

```

This:

```python
if isExist == 1:

```

Should be

```python
if isExist:

```

The same for the opposite:

```python
if isExist == 0:

```

should be:

```python
if not isExist:

```

Avoid making multiple read requests. These are blocking calls (the way you're calling them). I'm not sure how many items will be in your loop but say you have 30 iterations through the loop, that means at a minimum you would have 90 calls that are blocking your script from continuing until they return. This can quickly balloon out of control. Much like with the tag writes earlier you should (at a minimum) combine as many tag reads as you can into one call.

```python
tags = ['Is_Quality_Visible','Is_Performance_Visible','Is_Manual_Scrap']
tagPaths = ['{0}{1}/{2}/{3}'.format(configurationTagPath,Facility,Line,tag) for tag in tags]

isQuality,isPerformance,isManualScap = [tagValue.value for tagValue in system.tag.readBlocking(tagPaths)]

```

Throughout the script you consistently call `str()` on things that should already be strings. Might not seem like much but it will add time, and it all adds up. Definitely functions like `system.date.format()` should not be wrapped in a `str()` as they already return a string.

Speaking of `system.date.fomrat()` you should work with pure Date objects not strings. This would prevent you from needing to constantly use `system.date.parse()` through the script.

```python
if str(isPerformance) == 'None':

```

should be

```python
if isPerformance is None:

```

This net result of this

```auto
if(str(isPerformance) == 'None':
    isPerformance = 0
if(int(isPerfomrance) == 0:
   Performance = 1
else:
    #do something

```

Is that Performance will be 1 if isPerfomrance is None or 0, it should be:

```auto
if not isPerformance:
    Performance = 1
else:
    #do something

```

Honestly, this whole nested if structure can be refactored

```auto
if not isPerformance:
    Performance = 1
elif not targetUnit:
    Performance = float(totalCount) / float(targetUnit)
else:
    Performance = 0

```

Same thing for the quality

```auto
if not isQuality:
    Quality = 1
elif not totalCount and not scrapCount:
    Quality = 0
else:
    goodCount = toatlCount - scrapCount
    Quality = float(goodCount)/float(toatlCount)

```

There are similar issues in `getUnattededDT()` two notable things stick out.

For this:

```python
diffMinutes = int(system.date.format(startTime,'mm')) - int(system.date.format(endTime,'mm'))

```

Just do

```python
diffMinutes = system.date.minutesBetween(startTime,endTime)

```

pyDataSets give you the ability to use them in a more pythonic way and so things like this:

```auto
for f in range(len(dtDescdataset)):

```

should be something like:

```auto
for row in dtDescdataset:

```

And for this, all I can say is...Why?

```auto
int(1)

```

---

<div class="post-metadata">

**Author:** ![Sourabh\_Ambildhuke](https://avatars.discourse-cdn.com/v4/letter/s/f1d935/32.png) [@Sourabh\_Ambildhuke](https://forum.inductiveautomation.com/u/Sourabh_Ambildhuke)\
**Post date:** [June 16, 2023, 6:33pm UTC](https://forum.inductiveautomation.com/t/which-is-better-gateway-schedule-or-gateway-timer-script/75073/12 "2023-06-16T18:33:16Z")

</div>

Thanks @lrose for your input. We have worked on the script which you provided which has further enhanced the performance.
