This is an automated email from the ASF dual-hosted git repository.

pvillard31 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new d501315e053 NIFI-15900 Add optional timezone to plusDuration and 
minusDuration for DST-aware calendar arithmetic (#11296)
d501315e053 is described below

commit d501315e0536ba7252b2d4bba585bb0330d306cd
Author: Rakesh Kumar Singh <[email protected]>
AuthorDate: Wed Jun 3 02:36:22 2026 +0530

    NIFI-15900 Add optional timezone to plusDuration and minusDuration for 
DST-aware calendar arithmetic (#11296)
    
    When adding or subtracting calendar units (days, weeks, months, years) 
across DST
    boundaries, the result should preserve the wall-clock time rather than 
adding a
    fixed number of seconds. Previously, both functions always used the JVM 
system
    default timezone when converting the Date to a ZonedDateTime, which produced
    incorrect results when the desired timezone differed from the system 
default.
    
    Changes:
    - Add optional timezone parameter to plusDuration and minusDuration 
functions
      e.g. plusDuration('1 day', 'America/New_York')
    - Update ANTLR parser grammar to allow 1 or 2 arguments for these functions
    - AbstractDateArithmeticEvaluator uses the provided timezone (or system 
default)
      when performing calendar arithmetic
    - Add DST boundary test cases covering spring-forward and fall-back 
scenarios
---
 .../language/antlr/AttributeExpressionParser.g     |  5 ++-
 .../language/compile/ExpressionCompiler.java       | 10 +++++
 .../functions/AbstractDateArithmeticEvaluator.java | 41 ++++++++++++++++---
 .../functions/MinusDurationEvaluator.java          | 15 +++++--
 .../functions/PlusDurationEvaluator.java           | 15 +++++--
 .../attribute/expression/language/TestQuery.java   | 46 ++++++++++++++++++++++
 .../main/asciidoc/expression-language-guide.adoc   |  6 +++
 7 files changed, 125 insertions(+), 13 deletions(-)

diff --git 
a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g
 
b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g
index 7e8ee3f8c21..fd081dbe424 100644
--- 
a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g
+++ 
b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g
@@ -98,8 +98,9 @@ oneOrTwoArgBool : IS_VALID_DATE LPAREN! anyArg (COMMA! 
anyArg)? RPAREN!;
 zeroArgNum     : (LENGTH | TO_NUMBER | TO_DECIMAL | TO_MICROS | TO_NANOS | 
COUNT) LPAREN! RPAREN!;
 oneArgNum      : ((INDEX_OF | LAST_INDEX_OF) LPAREN! anyArg RPAREN!) |
                          ((MOD | PLUS | MINUS | MULTIPLY | DIVIDE) LPAREN! 
anyArg RPAREN!) |
-                         ((PLUS_DURATION | MINUS_DURATION | 
PLUS_INSTANT_DURATION | MINUS_INSTANT_DURATION) LPAREN! anyArg RPAREN!);
-oneOrTwoArgNum : MATH LPAREN! anyArg (COMMA! anyArg)? RPAREN!;
+                         ((PLUS_INSTANT_DURATION | MINUS_INSTANT_DURATION) 
LPAREN! anyArg RPAREN!);
+oneOrTwoArgNum : MATH LPAREN! anyArg (COMMA! anyArg)? RPAREN! |
+                 (PLUS_DURATION | MINUS_DURATION) LPAREN! anyArg (COMMA! 
anyArg)? RPAREN!;
 zeroOrOneOrTwoArgNum : TO_DATE LPAREN! anyArg? (COMMA! anyArg)? RPAREN!;
 zeroOrTwoArgNum: TO_INSTANT LPAREN! (anyArg COMMA! anyArg)? RPAREN!;
 
diff --git 
a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/compile/ExpressionCompiler.java
 
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/compile/ExpressionCompiler.java
index 4b9b34f6e1e..f833a37f3ce 100644
--- 
a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/compile/ExpressionCompiler.java
+++ 
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/compile/ExpressionCompiler.java
@@ -903,11 +903,21 @@ public class ExpressionCompiler {
                 }
             }
             case PLUS_DURATION: {
+                if (argEvaluators.size() == 2) {
+                    return addToken(new 
PlusDurationEvaluator(toDateEvaluator(subjectEvaluator),
+                            toStringEvaluator(argEvaluators.get(0)),
+                            toStringEvaluator(argEvaluators.get(1))), 
"plusDuration");
+                }
                 verifyArgCount(argEvaluators, 1, "plusDuration");
                 return addToken(new 
PlusDurationEvaluator(toDateEvaluator(subjectEvaluator),
                         toStringEvaluator(argEvaluators.get(0))), 
"plusDuration");
             }
             case MINUS_DURATION: {
+                if (argEvaluators.size() == 2) {
+                    return addToken(new 
MinusDurationEvaluator(toDateEvaluator(subjectEvaluator),
+                            toStringEvaluator(argEvaluators.get(0)),
+                            toStringEvaluator(argEvaluators.get(1))), 
"minusDuration");
+                }
                 verifyArgCount(argEvaluators, 1, "minusDuration");
                 return addToken(new 
MinusDurationEvaluator(toDateEvaluator(subjectEvaluator),
                         toStringEvaluator(argEvaluators.get(0))), 
"minusDuration");
diff --git 
a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/AbstractDateArithmeticEvaluator.java
 
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/AbstractDateArithmeticEvaluator.java
index 05d790ab661..187f3b940d8 100644
--- 
a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/AbstractDateArithmeticEvaluator.java
+++ 
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/AbstractDateArithmeticEvaluator.java
@@ -23,7 +23,9 @@ import 
org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
 import org.apache.nifi.attribute.expression.language.evaluation.QueryResult;
 import 
org.apache.nifi.attribute.expression.language.evaluation.literals.StringLiteralEvaluator;
 import 
org.apache.nifi.attribute.expression.language.evaluation.util.DateAmountParser;
+import 
org.apache.nifi.attribute.expression.language.exception.AttributeExpressionLanguageException;
 
+import java.time.DateTimeException;
 import java.time.ZoneId;
 import java.time.ZonedDateTime;
 import java.util.Date;
@@ -34,25 +36,42 @@ import java.util.Date;
  * <p>Handles literal-argument validation at construction time and the common
  * evaluate-and-convert logic. Subclasses only provide the arithmetic direction
  * via {@link #applyAmount(ZonedDateTime, String)}.</p>
+ *
+ * <p>An optional timezone evaluator may be provided so that DST-sensitive 
calendar units
+ * (days, weeks, months, years) are applied at the correct wall-clock time 
rather than
+ * as a fixed-length instant offset. When omitted, the system default timezone 
is used.</p>
  */
 abstract class AbstractDateArithmeticEvaluator extends DateEvaluator {
 
     private final Evaluator<Date> subject;
     private final Evaluator<String> amountEvaluator;
+    private final Evaluator<String> timeZoneEvaluator;
 
     /**
-     * @param subject         the date-producing evaluator to operate on
-     * @param amountEvaluator the evaluator producing the amount expression 
string
+     * @param subject           the date-producing evaluator to operate on
+     * @param amountEvaluator   the evaluator producing the amount expression 
string
+     * @param timeZoneEvaluator optional timezone evaluator (e.g. a timezone 
ID string); may be {@code null}
      */
     protected AbstractDateArithmeticEvaluator(final Evaluator<Date> subject,
-                                              final Evaluator<String> 
amountEvaluator) {
+                                              final Evaluator<String> 
amountEvaluator,
+                                              final Evaluator<String> 
timeZoneEvaluator) {
         this.subject = subject;
         this.amountEvaluator = amountEvaluator;
+        this.timeZoneEvaluator = timeZoneEvaluator;
 
         if (amountEvaluator instanceof StringLiteralEvaluator) {
             DateAmountParser.validate(
                     ((StringLiteralEvaluator) 
amountEvaluator).evaluate(null).getValue());
         }
+
+        if (timeZoneEvaluator instanceof StringLiteralEvaluator) {
+            final String tz = ((StringLiteralEvaluator) 
timeZoneEvaluator).evaluate(null).getValue();
+            try {
+                ZoneId.of(tz);
+            } catch (final DateTimeException e) {
+                throw new AttributeExpressionLanguageException("Invalid 
timezone identifier: " + tz, e);
+            }
+        }
     }
 
     /** Apply the date arithmetic — plus or minus — to the given date-time. */
@@ -66,8 +85,20 @@ abstract class AbstractDateArithmeticEvaluator extends 
DateEvaluator {
         }
 
         final String amountExpression = 
amountEvaluator.evaluate(evaluationContext).getValue();
-        final ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(
-                subjectValue.toInstant(), ZoneId.systemDefault());
+
+        ZoneId zoneId = ZoneId.systemDefault();
+        if (timeZoneEvaluator != null) {
+            final String tz = 
timeZoneEvaluator.evaluate(evaluationContext).getValue();
+            if (tz != null) {
+                try {
+                    zoneId = ZoneId.of(tz);
+                } catch (final DateTimeException e) {
+                    throw new AttributeExpressionLanguageException("Invalid 
timezone identifier: " + tz, e);
+                }
+            }
+        }
+
+        final ZonedDateTime zonedDateTime = 
ZonedDateTime.ofInstant(subjectValue.toInstant(), zoneId);
         final ZonedDateTime result = applyAmount(zonedDateTime, 
amountExpression);
 
         return new DateQueryResult(Date.from(result.toInstant()));
diff --git 
a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/MinusDurationEvaluator.java
 
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/MinusDurationEvaluator.java
index c95816b9fb0..1b3221a9430 100644
--- 
a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/MinusDurationEvaluator.java
+++ 
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/MinusDurationEvaluator.java
@@ -23,18 +23,27 @@ import java.time.ZonedDateTime;
 import java.util.Date;
 
 /**
- * Evaluator for {@code minusDuration('3 months')} — subtracts a 
calendar-aware amount from a Date.
+ * Evaluator for {@code minusDuration('3 months')} or {@code minusDuration('1 
day', 'America/Chicago')}
+ * — subtracts a calendar-aware amount from a Date, optionally in a specified 
timezone.
+ *
+ * <p>Providing a timezone is important for DST-sensitive units (days, weeks, 
months, years):
+ * subtracting "1 day" across a DST boundary should preserve wall-clock time, 
not subtract exactly 24 hours.</p>
  *
  * <p>Examples:</p>
  * <pre>
  *   ${date:toDate('dd-MM-yyyy'):minusDuration('1 month'):format('dd-MM-yyyy')}
- *   ${date:toDate('dd-MM-yyyy'):minusDuration('2 weeks')}
+ *   ${date:toDate('dd-MM-yyyy', 'America/Chicago'):minusDuration('1 day', 
'America/Chicago'):format('dd-MM-yyyy', 'America/Chicago')}
  * </pre>
  */
 public class MinusDurationEvaluator extends AbstractDateArithmeticEvaluator {
 
     public MinusDurationEvaluator(final Evaluator<Date> subject, final 
Evaluator<String> amountEvaluator) {
-        super(subject, amountEvaluator);
+        super(subject, amountEvaluator, null);
+    }
+
+    public MinusDurationEvaluator(final Evaluator<Date> subject, final 
Evaluator<String> amountEvaluator,
+                                  final Evaluator<String> timeZoneEvaluator) {
+        super(subject, amountEvaluator, timeZoneEvaluator);
     }
 
     @Override
diff --git 
a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/PlusDurationEvaluator.java
 
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/PlusDurationEvaluator.java
index fbb594f3d71..30b5b467b8e 100644
--- 
a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/PlusDurationEvaluator.java
+++ 
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/PlusDurationEvaluator.java
@@ -23,18 +23,27 @@ import java.time.ZonedDateTime;
 import java.util.Date;
 
 /**
- * Evaluator for {@code plusDuration('3 months')} — adds a calendar-aware 
amount to a Date.
+ * Evaluator for {@code plusDuration('3 months')} or {@code plusDuration('1 
day', 'America/New_York')}
+ * — adds a calendar-aware amount to a Date, optionally in a specified 
timezone.
+ *
+ * <p>Providing a timezone is important for DST-sensitive units (days, weeks, 
months, years):
+ * adding "1 day" across a DST boundary should preserve wall-clock time, not 
add exactly 24 hours.</p>
  *
  * <p>Examples:</p>
  * <pre>
  *   ${date:toDate('dd-MM-yyyy'):plusDuration('1 week'):format('dd-MM-yyyy')}
- *   ${date:toDate('dd-MM-yyyy'):plusDuration('2 years')}
+ *   ${date:toDate('dd-MM-yyyy', 'America/Chicago'):plusDuration('1 day', 
'America/Chicago'):format('dd-MM-yyyy', 'America/Chicago')}
  * </pre>
  */
 public class PlusDurationEvaluator extends AbstractDateArithmeticEvaluator {
 
     public PlusDurationEvaluator(final Evaluator<Date> subject, final 
Evaluator<String> amountEvaluator) {
-        super(subject, amountEvaluator);
+        super(subject, amountEvaluator, null);
+    }
+
+    public PlusDurationEvaluator(final Evaluator<Date> subject, final 
Evaluator<String> amountEvaluator,
+                                 final Evaluator<String> timeZoneEvaluator) {
+        super(subject, amountEvaluator, timeZoneEvaluator);
     }
 
     @Override
diff --git 
a/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java
 
b/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java
index f924a612202..825e636901a 100644
--- 
a/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java
+++ 
b/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java
@@ -3118,6 +3118,40 @@ public class TestQuery {
         final QueryResult<?> missingNoToDate = 
Query.compile("${missing:plusDuration('1 week')}")
                 .evaluate(new StandardEvaluationContext(attributes));
         assertNull(missingNoToDate.getValue());
+
+        // DST-aware: adding 1 day across a spring-forward DST boundary 
preserves wall-clock time
+        // 2026-03-29 00:00:00 CET (+01:00) + 1 day (DST-aware) = 2026-03-30 
00:00:00 CEST (+02:00)
+        // Without timezone context, this would add exactly 24 hours → wrong 
result due to the DST gap
+        attributes.put("dstDate", "2026-03-29 00:00:00");
+        verifyEquals(
+                "${dstDate:toDate('yyyy-MM-dd HH:mm:ss', 
'Europe/Vienna'):plusDuration('1 day', 'Europe/Vienna'):format('yyyy-MM-dd 
HH:mm:ssXXX', 'Europe/Vienna')}",
+                attributes,
+                "2026-03-30 00:00:00+02:00");
+
+        // DST-aware: adding 1 week across a spring-forward DST boundary 
preserves wall-clock time
+        verifyEquals(
+                "${dstDate:toDate('yyyy-MM-dd HH:mm:ss', 
'Europe/Vienna'):plusDuration('1 week', 'Europe/Vienna'):format('yyyy-MM-dd 
HH:mm:ssXXX', 'Europe/Vienna')}",
+                attributes,
+                "2026-04-05 00:00:00+02:00");
+
+        // DST-aware: subtracting 1 day while specifying a timezone preserves 
wall-clock time
+        attributes.put("fallDate", "2026-11-02 00:00:00");
+        verifyEquals(
+                "${fallDate:toDate('yyyy-MM-dd HH:mm:ss', 
'America/New_York'):minusDuration('1 day', 
'America/New_York'):format('yyyy-MM-dd HH:mm:ssXXX', 'America/New_York')}",
+                attributes,
+                "2026-11-01 00:00:00-04:00");
+
+        // Invalid literal timezone rejected at compile time
+        assertThrows(
+                AttributeExpressionLanguageException.class,
+                () -> 
Query.compile("${date:toDate('dd-MM-yyyy'):plusDuration('1 day', 
'America/Fake')}"));
+
+        // Invalid dynamic timezone rejected at evaluation time
+        attributes.put("tz", "NotAZone");
+        assertThrows(
+                AttributeExpressionLanguageException.class,
+                () -> 
Query.compile("${date:toDate('dd-MM-yyyy'):plusDuration('1 day', 
${tz}):format('dd-MM-yyyy')}")
+                        .evaluate(new StandardEvaluationContext(attributes)));
     }
 
     @Test
@@ -3289,6 +3323,18 @@ public class TestQuery {
         final QueryResult<?> missingNoToDate = 
Query.compile("${missing:minusDuration('1 week')}")
                 .evaluate(new StandardEvaluationContext(attributes));
         assertNull(missingNoToDate.getValue());
+
+        // Invalid literal timezone rejected at compile time
+        assertThrows(
+                AttributeExpressionLanguageException.class,
+                () -> 
Query.compile("${date:toDate('dd-MM-yyyy'):minusDuration('1 day', 
'America/Fake')}"));
+
+        // Invalid dynamic timezone rejected at evaluation time
+        attributes.put("tz", "NotAZone");
+        assertThrows(
+                AttributeExpressionLanguageException.class,
+                () -> 
Query.compile("${date:toDate('dd-MM-yyyy'):minusDuration('1 day', 
${tz}):format('dd-MM-yyyy')}")
+                        .evaluate(new StandardEvaluationContext(attributes)));
     }
 
     @Test
diff --git a/nifi-docs/src/main/asciidoc/expression-language-guide.adoc 
b/nifi-docs/src/main/asciidoc/expression-language-guide.adoc
index bdf8303513b..1f1e5ecf5dc 100644
--- a/nifi-docs/src/main/asciidoc/expression-language-guide.adoc
+++ b/nifi-docs/src/main/asciidoc/expression-language-guide.adoc
@@ -2590,6 +2590,7 @@ If the subject is null, the function returns null.
 *Arguments*:
 
 - [.argName]#_amount_# : [.argDesc]#A string in the form `"<number> <unit>"`. 
A space between the number and unit is required.#
+- [.argName]#_timezone_# (optional) : [.argDesc]#A timezone ID string (e.g. 
`"America/New_York"`, `"Europe/Vienna"`). When provided, calendar-unit 
arithmetic (days, weeks, months, years) is performed in the specified timezone 
so that wall-clock time is preserved across DST boundaries. When omitted, the 
JVM system default timezone is used.#
 
 *Supported Units*: nanosecond(s), second(s), minute(s), hour(s), day(s), 
week(s), month(s), year(s)
 
@@ -2609,6 +2610,7 @@ NOTE: Nanoseconds are accepted but have no effect on a 
`Date` subject because `j
 | `${date:toDate('dd-MM-yyyy'):plusDuration('3 months'):format('dd-MM-yyyy')}` 
| `04-11-2026`
 | `${date:toDate('dd-MM-yyyy'):plusDuration('2 hours'):format('dd-MM-yyyy 
HH:mm:ss')}` | `04-08-2026 02:00:00`
 | `${date:toDate('dd-MM-yyyy'):plusDuration('1 day')}` | Returns the epoch 
milliseconds for the resulting Date.
+| `${date:toDate('yyyy-MM-dd HH:mm:ss', 'Europe/Vienna'):plusDuration('1 day', 
'Europe/Vienna'):format('yyyy-MM-dd HH:mm:ssXXX', 'Europe/Vienna')}` (where 
date = `"2026-03-29 00:00:00"`) | `2026-03-30 00:00:00+02:00` (DST-aware: 
wall-clock time preserved across spring-forward)
 |============================================================================
 
 .Calendar-Aware Behavior
@@ -2617,6 +2619,7 @@ NOTE: Nanoseconds are accepted but have no effect on a 
`Date` subject because `j
 | Month-end clamping | Jan 31 + 1 month | Feb 28 (or Feb 29 in a leap year)
 | Leap year clamping | Feb 29, 2024 + 1 year | Feb 28, 2025
 | Crossing a day boundary | Aug 4 00:00:00 + 25 hours | Aug 5 01:00:00
+| DST spring-forward (with timezone) | Mar 29 00:00:00 CET + 1 day 
(Europe/Vienna) | Mar 30 00:00:00 CEST
 |============================================================================
 
 
@@ -2632,6 +2635,7 @@ If the subject is null, the function returns null.
 *Arguments*:
 
 - [.argName]#_amount_# : [.argDesc]#A string in the form `"<number> <unit>"`. 
A space between the number and unit is required.#
+- [.argName]#_timezone_# (optional) : [.argDesc]#A timezone ID string (e.g. 
`"America/New_York"`, `"Europe/Vienna"`). When provided, calendar-unit 
arithmetic (days, weeks, months, years) is performed in the specified timezone 
so that wall-clock time is preserved across DST boundaries. When omitted, the 
JVM system default timezone is used.#
 
 *Supported Units*: nanosecond(s), second(s), minute(s), hour(s), day(s), 
week(s), month(s), year(s)
 
@@ -2651,6 +2655,7 @@ NOTE: Nanoseconds are accepted but have no effect on a 
`Date` subject because `j
 | `${date:toDate('dd-MM-yyyy'):minusDuration('1 year'):format('dd-MM-yyyy')}` 
| `04-08-2025`
 | `${date:toDate('dd-MM-yyyy'):minusDuration('1 second'):format('dd-MM-yyyy 
HH:mm:ss')}` | `03-08-2026 23:59:59`
 | `${date:toDate('dd-MM-yyyy'):minusDuration('1 day')}` | Returns the epoch 
milliseconds for the resulting Date.
+| `${date:toDate('yyyy-MM-dd HH:mm:ss', 'America/New_York'):minusDuration('1 
day', 'America/New_York'):format('yyyy-MM-dd HH:mm:ssXXX', 
'America/New_York')}` (where date = `"2026-11-02 00:00:00"`) | `2026-11-01 
00:00:00-04:00` (DST-aware: wall-clock time preserved across fall-back)
 |============================================================================
 
 .Calendar-Aware Behavior
@@ -2659,6 +2664,7 @@ NOTE: Nanoseconds are accepted but have no effect on a 
`Date` subject because `j
 | Month-end clamping | Mar 31 - 1 month | Feb 28 (or Feb 29 in a leap year)
 | Leap year clamping | Feb 29, 2024 - 1 year | Feb 28, 2023
 | Crossing a day boundary | Aug 4 00:00:00 - 1 second | Aug 3 23:59:59
+| DST fall-back (with timezone) | Nov 2 00:00:00 EDT - 1 day 
(America/New_York) | Nov 1 00:00:00 EDT
 |============================================================================
 
 

Reply via email to