Select to view content in your preferred language

Arcade vs Time for local feature class

1283
8
08-16-2023 01:17 PM
Markbe_utco
New Contributor III

I'm simply trying to update a Date field with the current time. Ultimately I want to create an attribute rule that will automatically update the Date when a feature gets edited thus I have to use Arcade.

The following arcade functions all return a date value in UTC (six hours ahead of Mountain Time Zone):

- Now() --- returns date and time in UTC

- Date() --- returns date and time in UTC

- Timestamp() --- this is supposed to return a UTC value so....

- ToLocal(Timestamp()) --- returns date and time in UTC

- Today() --- Returns today's date but also sets the time to 6:00:00 AM - I'm not sure how this would get handled when the local time is past 6:00 pm and UTC time actually changes to the next day, I can only assume it would set the day to tomorrow's date and still set the time to 6:00:00 AM

Python's datetime.datetime.now() works just fine

Several of the function descriptions say, "Creates a date value in the local or system time of the client."  If the functions are actually working correctly what defines the client and how do I check its time setting?

It seems like it shouldn't be this difficult, am I missing something?

Any suggestions?

Edit: I've just tried this on my home computer with the same results.

8 Replies
Robert_LeClair
Esri Notable Contributor

So I was playing around with an Arcade expression via the Date functions | ArcGIS Arcade | ArcGIS Developers webpage and found these 3 lines of code will take the UTC time and subtract 6 hours for "local time."

var startDate = Date($feature.Date2);
var oneWeekLater = DateAdd(startDate, -6, 'hours');
return oneWeekLater;

Date2 is my date/time attribute field.  Ignore the var name of oneWeekLater as I was just modifying the -6 and hours component.  It worked for me in subtracting 6 hours from UTC for my CO time zone.

0 Kudos
Markbe_utco
New Contributor III

Yeah, I saw the DateAdd function, but you'd have to change it back and forth from -6 and -7 to account for daylight savings.  Ultimately I'd like to add this attribute rule to several feature classes, and having to change each rule on each feature class twice a year is just a begging for something to go wrong.   DateAdd may eventually be the workaround.

0 Kudos
Robert_LeClair
Esri Notable Contributor

I wonder if you could add an attribute rule based on the known dates of daylight savings?  Then based upon the date entered, it calculates the field using the Arcade function referenced above.  Related but perhaps not helpful is the RespectsDaylightSavingTime property in the ArcGIS Pro 3.1 API reference guide.

0 Kudos
Markbe_utco
New Contributor III

@Robert_LeClair wrote:

I wonder if you could add an attribute rule based on the known dates of daylight savings?


That's kind of what I'm working on at my workaround... the catch is trying to figure out the logic for the second Sunday in March and the first Sunday in November within the arcade script.

0 Kudos
Robert_LeClair
Esri Notable Contributor

Ya - that's the interesting part certainly.  I've been messing around with ChatGPT to write some Arcade / Python expressions/scripts for other workflows.  I haven't test this yet but this is the arcade expression that ChatGPT came up with:

var currentTime = $feature.TimeField; // Replace "TimeField" with your actual time field name
var currentDate = Date();
var timeZone = Timezone(currentDate, 'America/Denver'); // Mountain Time Zone

var dstStartDate = Date(Year(currentDate), 3, SecondSunday(3, 0, Year(currentDate)), 2, 0); // Second Sunday of March at 2:00 AM
var dstEndDate = Date(Year(currentDate), 11, FirstSunday(11, 0, Year(currentDate)), 2, 0); // First Sunday of November at 2:00 AM

if ((timeZone == -7 && currentTime >= dstStartDate) || (timeZone == -6 && currentTime < dstEndDate)) {
// Apply daylight saving time adjustment
return DateAdd(currentTime, 1, 'hours');
} else {
return currentTime;
}

Like I said, I've not tested this yet but it's a start on figuring out the catch/logic for the 2nd Sunday in March and the 1st Sunday in November.

Markbe_utco
New Contributor III

First off, thanks for the idea of writing functions for finding SecondSunday and FirstSunday.

Well, this is a rabbit hole I didn't think was this deep. Things were looking up until I started to debug the function for FirstSunday.  Apparently using Arcade to find the day of the week (Monday = 1 ... Sunday = 7) doesn't identify the first Sunday in November as a Sunday.  I can only assume it has to something to do with the change in Daylight Savings 🙄



Showing here (bolded text are the first Sundays in November of three different years)

console("*******" )
console(text(Date(2021, 10, 6))+" WeekDay = "+ text(ISOWeekday(Date(2021, 10, 6) ))) // Nov 6 2021
console(text(Date(2021, 10, 7))+" WeekDay = "+ text(ISOWeekday(Date(2021, 10, 7) ))) // Nov 7 2021
console(text(Date(2021, 10, 8))+" WeekDay = "+ text(ISOWeekday(Date(2021, 10, 8 ))) // Nov 8 2021
console("*******" )
console(text(Date(2022, 10, 5))+" WeekDay = "+ text(ISOWeekday(Date(2022, 10, 5) ))) // Nov 5 2022
console(text(Date(2022, 10, 6))+" WeekDay = "+ text(ISOWeekday(Date(2022, 10, 6) ))) // Nov 6 2022
console(text(Date(2022, 10, 7))+" WeekDay = "+ text(ISOWeekday(Date(2022, 10, 7) ))) // Nov 7 2022
console("*******" )
console(text(Date(2023, 10, 4))+" WeekDay = "+ text(ISOWeekday(Date(2023, 10, 4) ))) // Nov 4 2023
console(text(Date(2023, 10, 5))+" WeekDay = "+ text(ISOWeekday(Date(2023, 10, 5) ))) // Nov 5 2023
console(text(Date(2023, 10, 6))+" WeekDay = "+ text(ISOWeekday(Date(2023, 10, 6) ))) // Nov 6 2023
console("*******" )
console(text(Date(2023, 7, 4))+" WeekDay = "+ text(ISOWeekday(Date(2023, 7, 5) ))) // Aug 5 2021
console(text(Date(2023, 7, 5))+" WeekDay = "+ text(ISOWeekday(Date(2023, 7, 6) ))) // Aug 6 2021
console(text(Date(2023, 7, 6))+" WeekDay = "+ text(ISOWeekday(Date(2023, 7, 7) ))) // Aug 7 2021

Yields:

*******
2021-11-06T00:00:00-06:00 WeekDay = 6
2021-11-06T23:00:00-07:00 WeekDay = 6
2021-11-08T00:00:00-07:00 WeekDay = 1
*******
2022-11-05T00:00:00-06:00 WeekDay = 6
2022-11-05T23:00:00-07:00 WeekDay = 6
2022-11-07T00:00:00-07:00 WeekDay = 1
*******
2023-11-04T00:00:00-06:00 WeekDay = 6
2023-11-04T23:00:00-07:00 WeekDay = 6
2023-11-06T00:00:00-07:00 WeekDay = 1
*******
2023-08-04T00:00:00-06:00 WeekDay = 6
2023-08-05T00:00:00-06:00 WeekDay = 7
2023-08-06T00:00:00-06:00 WeekDay = 1

So now my work around will have to have the work around of finding the first Saturday in November then adding 1 to make it the first Sunday... SHEESH!!!

Silver lining: I'm learning more about Arcade Scripting than I expected to this week.  This is my first real foray into Arcade Scripting.... I'm less impressed!

 

Markbe_utco
New Contributor III

Here is some new information

When trying to populate a field in the attribute table using the following script it provides two different answers:

Now()      <-- populates the field with the current date & time in UTC
console(Now())    <-- populates the console window with the current date & time in local timetime

Timestamp()   <-- populates the field with the current date & time in UTC, this is what it is supposed to do
console(Timestamp())   <-- populates the console window with the current date & time in local timetime

ToLocal(Timestamp())  <-- populates the field with the current date & time in UTC, so what it is supposed to do
console(ToLocal(Timestamp()))  <-- populates the console window with the current date & time in local time, this is what it is supposed to do

0 Kudos
Markbe_utco
New Contributor III

Well, here is my workaround to obtaining local date/time values with the workaround for not being able to identify the first Sunday in November as a Sunday (

var currentDate = Timestamp() // current date & time in UTC
    
function MarchSecondSunday(inMonth, inYear){
    var sunday = 0 
    for(var x=0 ; x<=31 ; x++){
        if (ISOWeekday(Date(inYear, inMonth, x))==7){
            sunday = sunday + 1
            if(sunday == 2){
                return x
                break
            }
        }
    }
}


function NovemberFirstSaturday(inMonth, inYear){
    var saturday = 0 
    for (var y=0 ; y<=30 ; y++){
        if (ISOWeekday(Date(inYear, inMonth, y))==6){
            saturday = saturday + 1
            if(saturday == 1){
                console("saturday = " + saturday )
                return y+1
                break
            }
        }
    }
}


var dstStartDate = Date(Year(CurrentDate), 2, MarchSecondSunday(2, Year(currentDate))); // Second Sunday of March at 2:00 AM
var dstEndDate = Date(Year(CurrentDate), 10, NovemberFirstSaturday(10, Year(currentDate))); // First Sunday of November at 2:00 AM

if (currentDate < dstStartDate){
    console (dstStartDate + " ... Before DST Start ... " )
    return DateAdd(Timestamp(), -7, 'hours')
}
if ((currentDate >= dstStartDate) && (currentDate < dstEndDate)){
    console (dstStartDate+ " ... During DST ... " + dstEndDate)
	return DateAdd(Timestamp(), -6, 'hours')
}
if (currentDate >= dstEndDate){
    console ("After DST End ... " + dstEndDate)
    return DateAdd(Timestamp(), -7, 'hours')
}

 

0 Kudos