Here’s the transform for the offset, below. With this, you can then modify it to return now<offset> for dateMath (e.g. “now-4h”, “now-5h”). Gemini generated the code, and was smart enough to handle the southern hemisphere. We had to correct some of the syntax, of course…but the logic is sound.
You can also scale the Transform to handle multi-region with a lookup that maps the various startMonth/startSunday/…etc.
{
"name": "Flexible DST Offset",
"type": "static",
"attributes": {
"currentMonth": {
"type": "dateFormat",
"attributes": {
"inputFormat": "yyyy-MM-dd'T'HH:mm",
"outputFormat": "MM",
"input": {
"type": "dateMath",
"attributes": {
"expression": "now"
}
}
}
},
"currentDay": {
"type": "dateFormat",
"attributes": {
"inputFormat": "yyyy-MM-dd'T'HH:mm",
"outputFormat": "dd",
"input": {
"type": "dateMath",
"attributes": {
"expression": "now"
}
}
}
},
"currentDayOfWeek": {
"type": "dateFormat",
"attributes": {
"inputFormat": "yyyy-MM-dd'T'HH:mm",
"outputFormat": "u",
"input": {
"type": "dateMath",
"attributes": {
"expression": "now"
}
}
}
},
"currentUtcHour": {
"type": "dateFormat",
"attributes": {
"inputFormat": "yyyy-MM-dd'T'HH:mm",
"outputFormat": "HH",
"input": {
"type": "dateMath",
"attributes": {
"expression": "now"
}
}
}
},
"startMonth": "3",
"startSunday": "2",
"startUtcHour": "7",
"endMonth": "11",
"endSunday": "1",
"endUtcHour": "6",
"stdOffset": "-5",
"dstOffset": "-4",
"value": "#set($number = 1)#set($m = $number.parseInt($currentMonth))#set($d = $number.parseInt($currentDay))#set($dw = $number.parseInt($currentDayOfWeek))#set($uh = $number.parseInt($currentUtcHour))#set($sM = $number.parseInt($startMonth))#set($sS = $number.parseInt($startSunday))#set($sH = $number.parseInt($startUtcHour))#set($eM = $number.parseInt($endMonth))#set($eS = $number.parseInt($endSunday))#set($eH = $number.parseInt($endUtcHour))#set($lastSun = $d - $dw)#set($isDST = false)#if($sM < $eM) #if($m > $sM && $m < $eM) #set($isDST = true) #elseif($m == $sM) #set($startBound = ($sS * 7) - 6) #if($lastSun > $startBound || ($lastSun == $startBound && $uh >= $sH)) #set($isDST = true) #end #elseif($m == $eM) #set($endBound = ($eS * 7) - 6) #if($lastSun < $endBound || ($lastSun == $endBound && $uh < $eH)) #set($isDST = true) #end #end#{else} #if($m > $sM || $m < $eM) #set($isDST = true) #elseif($m == $sM) #set($startBound = ($sS * 7) - 6) #if($lastSun > $startBound || ($lastSun == $startBound && $uh >= $sH)) #set($isDST = true) #end #elseif($m == $eM) #set($endBound = ($eS * 7) - 6) #if($lastSun < $endBound || ($lastSun == $endBound && $uh < $eH)) #set($isDST = true) #end #end #end #if($isDST) $dstOffset #{else} $stdOffset #end"
}
}
The formatted velocity code:
#set($number = 1)
#set($m = $number.parseInt($currentMonth))
#set($d = $number.parseInt($currentDay))
#set($dw = $number.parseInt($currentDayOfWeek))
#set($uh = $number.parseInt($currentUtcHour))
#set($sM = $number.parseInt($startMonth))
#set($sS = $number.parseInt($startSunday))
#set($sH = $number.parseInt($startUtcHour))
#set($eM = $number.parseInt($endMonth))
#set($eS = $number.parseInt($endSunday))
#set($eH = $number.parseInt($endUtcHour))
#set($lastSun = $d - $dw)
#set($isDST = false)
#if($sM < $eM)
#if($m > $sM && $m < $eM)
#set($isDST = true)
#elseif($m == $sM)
#set($startBound = ($sS * 7) - 6)
#if($lastSun > $startBound || ($lastSun == $startBound && $uh >= $sH))
#set($isDST = true)
#end #elseif($m == $eM)
#set($endBound = ($eS * 7) - 6)
#if($lastSun < $endBound || ($lastSun == $endBound && $uh < $eH))
#set($isDST = true)
#end
#end
#{else}
#if($m > $sM || $m < $eM)
#set($isDST = true)
#elseif($m == $sM)
#set($startBound = ($sS * 7) - 6)
#if($lastSun > $startBound || ($lastSun == $startBound && $uh >= $sH))
#set($isDST = true)
#end
#elseif($m == $eM)
#set($endBound = ($eS * 7) - 6)
#if($lastSun < $endBound || ($lastSun == $endBound && $uh < $eH))
#set($isDST = true)
#end
#end
#end
#if($isDST)
$dstOffset
#{else}
$stdOffset
#end
From Gemini:
Mind you though, this definitely is, IMO, a bit of an over-engineered solution just to get dynamic timezone offset. Depending on the scale of your deployment / population, they may / may not be a suitable / efficient solution.