Pop-up expression

734
10
03-19-2018 04:24 PM
WhitneyLoy
New Contributor III

Hi-

I am using the labeling from this link for my street sweeping application and the date is incorrect

Create Map - My Government Services | ArcGIS for Local Government 

It is returning the same for routes with different sweep days. Example, sweep day for route 12 is Friday, but is returning a date of 3/25 and route 7 has a sweep day of Wednesday, but the expression is returning 3/25 as well.

Thanks!!

The code is below:

/*If the cleaning isn't available year-round 
specify the first and last day of the season that cleaning will occur*/ 
var openSeason = [[1,1],[12,31]]

var cleaningWeek = [];
var cleaningWeekFields = [$feature.WEEKONE, $feature.WEEKTWO,
                          $feature.WEEKTHREE, $feature.WEEKFOUR]
for (var k in cleaningWeekFields) {
    if (cleaningWeekFields == 'Yes') {
        cleaningWeek[Count(cleaningWeek)] = k;
    }
}
if (Count(cleaningWeek)    == 0)
    return;
    
function getNextCleaningWeek(fromDate) {
    var firstSundayCurrentMonth = Date(Year(fromDate), Month(fromDate), 1);
    var firstWeekday = Weekday(firstSundayCurrentMonth);
    if (firstWeekday > 0)
        firstSundayCurrentMonth = DateAdd(firstSundayCurrentMonth, 7 - firstWeekday, 'days');
    for (var k in cleaningWeek) {
        var startCleaningWeek = DateAdd(firstSundayCurrentMonth, (cleaningWeek*7), 'days');
        if (fromDate <= startCleaningWeek)
            return [startCleaningWeek, DateAdd(startCleaningWeek, 6, 'days')];
    }
    
    var firstSundayNextMonth = Date(Year(fromDate), Month(fromDate) + 1, 1);
    var firstWeekday = Weekday(firstSundayNextMonth);
    if (firstWeekday > 0)
        firstSundayNextMonth = DateAdd(firstSundayNextMonth, 7 - firstWeekday, 'days');
    var startCleaningWeek = DateAdd(firstSundayNextMonth, (7 * cleaningWeek[0]), 'days');
    return [startCleaningWeek, DateAdd(startCleaningWeek, 6, 'days')];
}
    
function validateSeasonCleaning(cleaningWeek) {
    var startSeasonMonth = openSeason[0][0]-1;
    var startSeasonDay = openSeason[0][1];
    var endSeasonMonth = openSeason[1][0]-1;
    var endSeasonDay = openSeason[1][1];
    
    if (Date(Year(cleaningWeek[1]), startSeasonMonth, startSeasonDay) > Date(Year(cleaningWeek[1]), endSeasonMonth, endSeasonDay)) {
        if (cleaningWeek[1] < Date(Year(cleaningWeek[1]), startSeasonMonth, startSeasonDay) && cleaningWeek[1] > Date(Year(cleaningWeek[1]) - 1, endSeasonMonth, endSeasonDay))
            cleaningWeek = getNextCleaningWeek(Date(Year(cleaningWeek[1]), startSeasonMonth, startSeasonDay))
    }
    else {
        if (cleaningWeek[1] < Date(Year(cleaningWeek[1]), startSeasonMonth, startSeasonDay))
            cleaningWeek = getNextCleaningWeek(Date(Year(cleaningWeek[1]), startSeasonMonth, startSeasonDay));
        else if (cleaningWeek[1] > Date(Year(cleaningWeek[1]), endSeasonMonth, endSeasonDay))
            cleaningWeek = getNextCleaningWeek(Date(Year(cleaningWeek[1]) + 1, startSeasonMonth, startSeasonDay));
    }
    return cleaningWeek;
}

var nextCleaning = getNextCleaningWeek(Today());
nextCleaning = validateSeasonCleaning(nextCleaning);
return Text(nextCleaning[0], 'MMMM D, YYYY');
0 Kudos
10 Replies
XanderBakker
Esri Esteemed Contributor

Can you use these instructions (https://community.esri.com/docs/DOC-8691-posting-code-with-syntax-highlighting-on-geonet )  to edit your post (use Javascript as language) and insert the code using the correct indentation? It is very difficult to interpret the code as it is. There is one thing to keep in mind. When you create a date the month is a value in the range from 0 to 11, not 1 to 12.

I have done something similar for sweeping streets of Medellín:

http://utility-esri-co.maps.arcgis.com/apps/Styler/index.html?appid=d69c88aacf9a47d0bf9a3ea8bf16c590 

And something for the collection of solid waste:

http://utility-esri-co.maps.arcgis.com/apps/View/index.html?appid=c381a2e150ef4e4cb62b4027a31e0d45 

0 Kudos
WhitneyLoy
New Contributor III

I posted the code again per your suggestion, thanks. I checked out the solid waste collection app you created, pretty cool. I am trying to do the same thing. 

0 Kudos
XanderBakker
Esri Esteemed Contributor

Hi Whitney Loy , can you also include some test values for: 

$feature.WEEKONE, $feature.WEEKTWO, $feature.WEEKTHREE and $feature.WEEKFOUR

... and the expected outcome for nextCleaning[0]?

That will allow me to track down what might be going wrong.

0 Kudos
WhitneyLoy
New Contributor III

I think I am confused I copied the wrong code. My bad. The issue I am having is my routes very by week. 

This is what I am using:

/*If pickup occurs weekly, specify 1. 
If every other week specify 2, etc.*/
var pickupWeekInterval = 1;

/*Specify a date in the past in which pickup occurred.
This is used in the case where pickup doesn't occur every week 
to determine the weeks where pickup is occurring.*/
var firstPickupWeek = Date('2017-01-01');

/*If the pickup service isn't available year-round 
specify the first and last day of the season that pickup will occur, [[Start Month, Start Day], [[End Month, End Day]]*/ 
var openSeason = [[1,1],[12,31]]

//Specify any holidays where pickup will not occur, [Month, Day]
var holidays = [[1,1],[7,4],[12,25]] 

/*Specify any variable holidays where pickup will not occur, [Occurrence, Month, Day of the Week (Sunday = 0, Saturday = 6)]
These are holidays that don't fall on the same date every year, i.e. Memorial Day, Labor Day, Thanksgiving
[-1,5,1] corresponds to Memorial Day -> Last occurrence in May of a Monday
[1,9,1] corresponds to Labor Day -> 1st occurrence in September of a Monday 
[4,11,4] corresponds to Thanksgiving -> 4th occurrence in November of a Thursday*/
var variableHolidays = [[-1,5,1],[1,9,1],[4,11,4]]; 

/*Specify if the next scheduled pickup day falls on a holiday, when will the next actual pickup be.
"Next Weekday" - The pickup will occur on the next weekday after the holiday
"Next Day" - The pickup will occur on the next day after the holiday
"Next Scheduled Pickup" - The pickup will occur on the next scheduled day after the holiday*/
var nextPickupHoliday = "Next Weekday";

var pickupDays = [];
var pickupDaysFields = [$feature.SUNDAY, $feature.MONDAY, $feature.TUESDAY,
                              $feature.WEDNESDAY, $feature.THURSDAY,
                              $feature.FRIDAY, $feature.SATURDAY]
for (var k in pickupDaysFields) {
     if (pickupDaysFields == 'Yes') {
          pickupDays[Count(pickupDays)] = k;
     }
}               
if (Count(pickupDays) == 0)
     return;               

function calcRelativeHoliday(week, month, day, year) {
     var holiday;
     if (week < 0){
          var lastDay = DateAdd(Date(year, month + 1, 1), -1, 'days');
          var dayOfWeek = Weekday(lastDay);
          var dayDiff = day - dayOfWeek;
          if (dayDiff > 0) 
               dayDiff -= 7;
          holiday = DateAdd(lastDay, dayDiff + ((week + 1) * 7), 'days');
     }
     else{
          var firstDay = Date(year, month, 1);
          var dayOfWeek = Weekday(firstDay);
          var dayDiff = day - dayOfWeek;
          if (dayDiff < 0) 
               dayDiff += 7;
          holiday = DateAdd(firstDay, dayDiff + ((week - 1) * 7), 'days');     
     }
     return holiday;
}

function getNextPickupDay(fromDate) {
     var currentDay = Weekday(fromDate);
     var pickupOffset = 0;
     if (pickupWeekInterval > 1){
          var weekDif = DateDiff(DateAdd(fromDate, 0 - currentDay, 'days'), 
                              DateAdd(firstPickupWeek, 0 - Weekday(firstPickupWeek), 'days'),
                              'days') / 7;
          
          weekDif = weekDif % pickupWeekInterval;
          if (weekDif > 0)
               pickupOffset = pickupWeekInterval - weekDif;
     }

     var difDays;
     var nextPickupDay;
     if (pickupOffset > 0) {
          nextPickupDay = pickupDays[0];
          difDays = nextPickupDay - currentDay;
          difDays += (7 * pickupOffset);
     }
     else {
          for(var k in pickupDays) {
               if (pickupDays >= currentDay) {
                    nextPickupDay = pickupDays;
                    break;
               }
          }
          
          if (IsEmpty(nextPickupDay))
               nextPickupDay = pickupDays[0];
               
          difDays = nextPickupDay - currentDay;
          if (nextPickupDay < currentDay)
               difDays += (7 * pickupWeekInterval); 
     }
     return DateAdd(fromDate, difDays, 'days');     
}

function getHolidays(fromDate) {
     var holidayDates = [];
     for (var k in holidays) {
          var holiday = Date(Year(fromDate), holidays[0] -1, holidays[1]);
          if (holiday < fromDate)
               holiday = Date(Year(fromDate) + 1, holidays[0] -1, holidays[1]);
          holidayDates = holiday;
     }
     for (var k in variableHolidays) {
          var x = variableHolidays;
          var holiday = calcRelativeHoliday(x[0], x[1]-1, x[2], Year(fromDate));
          if (holiday < fromDate)
               holiday = calcRelativeHoliday(x[0], x[1]-1, x[2], Year(fromDate) + 1);
          holidayDates[Count(holidayDates)] = holiday;
     }
     return holidayDates;
}

function validateSeasonPickup(pickupDate) {
     var startSeasonMonth = openSeason[0][0]-1;
     var startSeasonDay = openSeason[0][1];
     var endSeasonMonth = openSeason[1][0]-1;
     var endSeasonDay = openSeason[1][1];
     
     if (Date(Year(pickupDate), startSeasonMonth, startSeasonDay) > Date(Year(pickupDate), endSeasonMonth, endSeasonDay)) {
          if (pickupDate < Date(Year(pickupDate), startSeasonMonth, startSeasonDay) && pickupDate > Date(Year(pickupDate) - 1, endSeasonMonth, endSeasonDay))
               pickupDate = getNextPickupDay(Date(Year(pickupDate), startSeasonMonth, startSeasonDay))
     }
     else {
          if (pickupDate < Date(Year(pickupDate), startSeasonMonth, startSeasonDay))
               pickupDate = getNextPickupDay(Date(Year(pickupDate), startSeasonMonth, startSeasonDay));
          else if (pickupDate > Date(Year(pickupDate), endSeasonMonth, endSeasonDay))
               pickupDate = getNextPickupDay(Date(Year(pickupDate) + 1, startSeasonMonth, startSeasonDay));
     }
     return pickupDate;
}

function validateHolidayPickup(pickupDate, holidayDates) {
     for(var k in holidayDates) {
          if (pickupDate == holidayDates) {
               if (nextPickupHoliday == "Next Scheduled Pickup") {
                    pickupDate = getNextPickupDay(DateAdd(pickupDate, 1, 'days'));
               }
               else if (nextPickupHoliday == "Next Day") {
                    pickupDate = DateAdd(pickupDate, 1, 'days');
               }
               else if (nextPickupHoliday == "Next Weekday") {
                    var currentDay = Weekday(pickupDate);
                    if (currentDay > 4) {
                         pickupDate = DateAdd(pickupDate, 8 - currentDay, 'days');
                    }
                    else {
                         pickupDate = DateAdd(pickupDate, 1, 'days');
                    }                         
               }
               break;
          }
     }
     return pickupDate
}

var nextPickup = getNextPickupDay(Today());
nextPickup = validateSeasonPickup(nextPickup);
nextPickup = validateHolidayPickup(nextPickup, getHolidays(nextPickup));
return Text(nextPickup, 'dddd, MMMM D');
0 Kudos
XanderBakker
Esri Esteemed Contributor

OK, thanks for sharing the other script. Can you provide some sample values for:

$feature.SUNDAY,

$feature.MONDAY,

$feature.TUESDAY,
$feature.WEDNESDAY,

$feature.THURSDAY,
$feature.FRIDAY,

$feature.SATURDAY

... and the corresponding expected values for the resulting nextPickup

0 Kudos
WhitneyLoy
New Contributor III
0 Kudos
XanderBakker
Esri Esteemed Contributor

Hi Whitney Loy ,

Thanks for sharing the data, but be careful since it is editable. I just did a small test with a list containing Monday and Thursday and it yielded Thursday, March 22 (in Spanish), which would be correct. I will do a test linking directly to the data to see what the result is. 

0 Kudos
XanderBakker
Esri Esteemed Contributor

Just did a test against your data in ArcGIS Online and it seems to provide the correct result:

I didn't change anything in your code just added some Console statements:

/*If pickup occurs weekly, specify 1. 
If every other week specify 2, etc.*/
var pickupWeekInterval = 1;

/*Specify a date in the past in which pickup occurred.
This is used in the case where pickup doesn't occur every week 
to determine the weeks where pickup is occurring.*/
var firstPickupWeek = Date('2017-01-01');

/*If the pickup service isn't available year-round 
specify the first and last day of the season that pickup will occur, [[Start Month, Start Day], [[End Month, End Day]]*/ 
var openSeason = [[1,1],[12,31]]

//Specify any holidays where pickup will not occur, [Month, Day]
var holidays = [[1,1],[7,4],[12,25]] 

/*Specify any variable holidays where pickup will not occur, [Occurrence, Month, Day of the Week (Sunday = 0, Saturday = 6)]
These are holidays that don't fall on the same date every year, i.e. Memorial Day, Labor Day, Thanksgiving
[-1,5,1] corresponds to Memorial Day -> Last occurrence in May of a Monday
[1,9,1] corresponds to Labor Day -> 1st occurrence in September of a Monday 
[4,11,4] corresponds to Thanksgiving -> 4th occurrence in November of a Thursday*/
var variableHolidays = [[-1,5,1],[1,9,1],[4,11,4]]; 

/*Specify if the next scheduled pickup day falls on a holiday, when will the next actual pickup be.
"Next Weekday" - The pickup will occur on the next weekday after the holiday
"Next Day" - The pickup will occur on the next day after the holiday
"Next Scheduled Pickup" - The pickup will occur on the next scheduled day after the holiday*/
var nextPickupHoliday = "Next Weekday";

var pickupDays = [];
var pickupDaysFields = [$feature.SUNDAY, $feature.MONDAY, $feature.TUESDAY,
                              $feature.WEDNESDAY, $feature.THURSDAY,
                              $feature.FRIDAY, $feature.SATURDAY]

// var pickupDaysFields = ['No', 'Yes', 'No', 'No', 'Yes', 'No', 'No']       
Console("pickupDaysFields (Sun-Sat):" + pickupDaysFields);
                                     
for (var k in pickupDaysFields) {
     if (pickupDaysFields[k] == 'Yes') {
          pickupDays[Count(pickupDays)] = k;
     }
}               
if (Count(pickupDays) == 0)
     return;               

Console("pickupDays:" + pickupDays); 
 
function calcRelativeHoliday(week, month, day, year) {
     var holiday;
     if (week < 0){
          var lastDay = DateAdd(Date(year, month + 1, 1), -1, 'days');
          var dayOfWeek = Weekday(lastDay);
          var dayDiff = day - dayOfWeek;
          if (dayDiff > 0) 
               dayDiff -= 7;
          holiday = DateAdd(lastDay, dayDiff + ((week + 1) * 7), 'days');
     }
     else{
          var firstDay = Date(year, month, 1);
          var dayOfWeek = Weekday(firstDay);
          var dayDiff = day - dayOfWeek;
          if (dayDiff < 0) 
               dayDiff += 7;
          holiday = DateAdd(firstDay, dayDiff + ((week - 1) * 7), 'days');     
     }
      Console("calcRelativeHoliday::holiday:" + holiday);
     return holiday;
}

function getNextPickupDay(fromDate) {
     var currentDay = Weekday(fromDate);
     var pickupOffset = 0;
     if (pickupWeekInterval > 1){
          var weekDif = DateDiff(DateAdd(fromDate, 0 - currentDay, 'days'), 
                              DateAdd(firstPickupWeek, 0 - Weekday(firstPickupWeek), 'days'),
                              'days') / 7;
          
          weekDif = weekDif % pickupWeekInterval;
          if (weekDif > 0)
               pickupOffset = pickupWeekInterval - weekDif;
     }

     var difDays;
     var nextPickupDay;
     if (pickupOffset > 0) {
          nextPickupDay = pickupDays[0];
          difDays = nextPickupDay - currentDay;
          difDays += (7 * pickupOffset);
     }
     else {
          for(var k in pickupDays) {
               if (pickupDays[k] >= currentDay) {
                    nextPickupDay = pickupDays[k];
                    break;
               }
          }
          
          if (IsEmpty(nextPickupDay))
               nextPickupDay = pickupDays[0];
               
          difDays = nextPickupDay - currentDay;
          if (nextPickupDay < currentDay)
               difDays += (7 * pickupWeekInterval); 
     }
      Console("getNextPickupDay:" + DateAdd(fromDate, difDays, 'days'));
     return DateAdd(fromDate, difDays, 'days');     
}

function getHolidays(fromDate) {
     var holidayDates = [];
     for (var k in holidays) {
          var holiday = Date(Year(fromDate), holidays[k][0] -1, holidays[k][1]);
          if (holiday < fromDate)
               holiday = Date(Year(fromDate) + 1, holidays[k][0] -1, holidays[k][1]);
          holidayDates[k] = holiday;
     }
     for (var k in variableHolidays) {
          var x = variableHolidays[k];
          var holiday = calcRelativeHoliday(x[0], x[1]-1, x[2], Year(fromDate));
          if (holiday < fromDate)
               holiday = calcRelativeHoliday(x[0], x[1]-1, x[2], Year(fromDate) + 1);
          holidayDates[Count(holidayDates)] = holiday;
     }
      Console("getHolidays::holidayDates:" +  holidayDates);
     return holidayDates;
}

function validateSeasonPickup(pickupDate) {
     var startSeasonMonth = openSeason[0][0]-1;
     var startSeasonDay = openSeason[0][1];
     var endSeasonMonth = openSeason[1][0]-1;
     var endSeasonDay = openSeason[1][1];
     
     if (Date(Year(pickupDate), startSeasonMonth, startSeasonDay) > Date(Year(pickupDate), endSeasonMonth, endSeasonDay)) {
          if (pickupDate < Date(Year(pickupDate), startSeasonMonth, startSeasonDay) && pickupDate > Date(Year(pickupDate) - 1, endSeasonMonth, endSeasonDay))
               pickupDate = getNextPickupDay(Date(Year(pickupDate), startSeasonMonth, startSeasonDay))
     }
     else {
          if (pickupDate < Date(Year(pickupDate), startSeasonMonth, startSeasonDay))
               pickupDate = getNextPickupDay(Date(Year(pickupDate), startSeasonMonth, startSeasonDay));
          else if (pickupDate > Date(Year(pickupDate), endSeasonMonth, endSeasonDay))
               pickupDate = getNextPickupDay(Date(Year(pickupDate) + 1, startSeasonMonth, startSeasonDay));
     }
      Console("validateSeasonPickup::pickupDate:" + pickupDate)
     return pickupDate;
}

function validateHolidayPickup(pickupDate, holidayDates) {
     for(var k in holidayDates) {
          if (pickupDate == holidayDates[k]) {
               if (nextPickupHoliday == "Next Scheduled Pickup") {
                    pickupDate = getNextPickupDay(DateAdd(pickupDate, 1, 'days'));
               }
               else if (nextPickupHoliday == "Next Day") {
                    pickupDate = DateAdd(pickupDate, 1, 'days');
               }
               else if (nextPickupHoliday == "Next Weekday") {
                    var currentDay = Weekday(pickupDate);
                    if (currentDay > 4) {
                         pickupDate = DateAdd(pickupDate, 8 - currentDay, 'days');
                    }
                    else {
                         pickupDate = DateAdd(pickupDate, 1, 'days');
                    }                         
               }
               break;
          }
     }
      Console("validateHolidayPickup::pickupDate:" + pickupDate);
     return pickupDate
}

var nextPickup = getNextPickupDay(Today());
Console("nextPickup (1):" + nextPickup);
nextPickup = validateSeasonPickup(nextPickup);
Console("nextPickup (2):" + nextPickup);
nextPickup = validateHolidayPickup(nextPickup, getHolidays(nextPickup));
Console("nextPickup (3):" + nextPickup);
Console("return:" + Text(nextPickup, 'dddd, MMMM D'));
return Text(nextPickup, 'dddd, MMMM D');‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

This is returned to the Console:

pickupDaysFields (Sun-Sat):[null,null,null,null,"Yes",null,null]
pickupDays:[4]
getNextPickupDay:2018-03-22T00:00:00-05:00
nextPickup (1):2018-03-22T00:00:00-05:00
validateSeasonPickup::pickupDate:2018-03-22T00:00:00-05:00
nextPickup (2):2018-03-22T00:00:00-05:00
calcRelativeHoliday::holiday:2018-05-28T00:00:00-05:00
calcRelativeHoliday::holiday:2018-09-03T00:00:00-05:00
calcRelativeHoliday::holiday:2018-11-22T00:00:00-05:00
getHolidays::holidayDates:["2019-01-01T00:00:00-05:00","2018-07-04T00:00:00-05:00","2018-12-25T00:00:00-05:00","2018-05-28T00:00:00-05:00","2018-09-03T00:00:00-05:00","2018-11-22T00:00:00-05:00"]
validateHolidayPickup::pickupDate:2018-03-22T00:00:00-05:00
nextPickup (3):2018-03-22T00:00:00-05:00
return:Thursday, March 22
0 Kudos
KristianEkenes
Esri Regular Contributor

If one of these expressions is working, you should consider adding it as a template to the arcade-expressions repo so others can benefit from it: GitHub - Esri/arcade-expressions: ArcGIS Arcade expression templates for all supported profiles in t... 

Here's a blog post describing the repo: Share your Arcade expressions as templates | ArcGIS Blog