commit e7e1ff19327d362e40df77cf03bcd8e235858733
Author: Fredrik Öhrström <oehrstroem@gmail.com>
Date:   Mon May 11 22:01:01 2026 +0200

    Fix so you can add 1y to a date.

diff --git a/src/testinternals.cc b/src/testinternals.cc
index d946da26..ceef8e1d 100644
--- a/src/testinternals.cc
+++ b/src/testinternals.cc
@@ -56,6 +56,7 @@ bool verbose_ = false;
     X(device_parsing) \
     X(meters)         \
     X(months)         \
+    X(years)          \
     X(aes)            \
     X(sbc)            \
     X(hex)            \
@@ -1218,7 +1219,7 @@ void test_month(int y, int m, int day, int mdiff, string from, string to)
         os != to)
     {
         printf("ERROR! Expected %s + %d months should be %s\n"
-               "But got %s - 11 = %s\n",
+               "But got %s != %s\n",
                from.c_str(), mdiff, to.c_str(),
                s.c_str(), os.c_str());
     }
@@ -1242,6 +1243,45 @@ void test_months()
     test_month(2000,02,29, 12*100, "2000-02-29", "2100-02-28");
 }
 
+void test_year(int y, int m, int day, int ydiff, string from, string to)
+{
+    struct tm date {};
+    date.tm_year  = y-1900;
+    date.tm_mon   = m-1;
+    date.tm_mday  = day;
+
+    string s = strdate(&date);
+
+    struct tm d;
+    d = date;
+    addYears(&d, ydiff);
+
+    string os = strdate(&d);
+
+    if (s != from ||
+        os != to)
+    {
+        printf("ERROR! Expected %s + %d years should be %s\n"
+               "But got %s != %s\n",
+               from.c_str(), ydiff, to.c_str(),
+               s.c_str(), os.c_str());
+    }
+}
+
+
+void test_years()
+{
+    test_year(2020,12,31, 2, "2020-12-31", "2022-12-31");
+    test_year(2020,12,31, -2, "2020-12-31", "2018-12-31");
+    test_year(1900,01,01, 222, "1900-01-01", "2122-01-01");
+    // 2020 was a leap year.
+    test_year(2021,02,28, -1, "2021-02-28", "2020-02-29");
+    // 2000 was a leap year %100=0 but %400=0 overrides.
+    test_year(2001,02,28, -1, "2001-02-28", "2000-02-29");
+    // 2100 is not a leap year since %100=0 and not overriden %400 != 0.
+    test_year(2000,02,29, 100, "2000-02-29", "2100-02-28");
+}
+
 // Vatten    multical21:BUS1:c1 12345678 KEY
 // Tempmeter piigth(info=123):BUS2:2400   0        NOKEY
 
@@ -2785,6 +2825,9 @@ void test_formulas_datetimes()
     test_datetime(f.get(), "'2021-01-31' + 24month", 2023, 1, 31);
     test_datetime(f.get(), "'2021-01-31' + 22month", 2022, 11, 30);
 
+    test_datetime(f.get(), "'2021-01-31' + 2y", 2023, 01, 31);
+    test_datetime(f.get(), "'2000-01-01' + 24y + 5month + 3d", 2024, 6, 4);
+
     // 2020 was a leap year.
     test_datetime(f.get(), "'2021-02-28' -12month", 2020,2,29);
     // 2000 was a leap year %100=0 but %400=0 overrides.
diff --git a/src/units.cc b/src/units.cc
index df1f667e..3a7f6017 100644
--- a/src/units.cc
+++ b/src/units.cc
@@ -367,13 +367,22 @@ bool SIUnit::mathOpTo(MathOp op, double left, double right, const SIUnit &right_
         }
         if (right_siunit.exp() == SI_Month.exp())
         {
-            // Move right argument (day, hour, min, s) to seconds.
             if (op == MathOp::SUB) right = -right;
+            // We must use the addMonths function since months have different lengths.
             double result = addMonths(left, right);
             if (out_siunit != NULL) *out_siunit = SI_UnixTimestamp;
             if (out != NULL) *out = result;
             return true;
         }
+        if (right_siunit.exp() == SI_Year.exp())
+        {
+            if (op == MathOp::SUB) right = -right;
+            // We must use the addYears function since years have different lengths (leap years).
+            double result = addYears(left, right);
+            if (out_siunit != NULL) *out_siunit = SI_UnixTimestamp;
+            if (out != NULL) *out = result;
+            return true;
+        }
     }
 
     // Oups, should not get here....
diff --git a/src/util.cc b/src/util.cc
index 5ce0b18b..af4fcf3d 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -886,6 +886,16 @@ void addMonths(struct tm *date, int months)
     date->tm_mday = day;
 }
 
+double addYears(double t, int y)
+{
+    return addMonths(t, y*12);
+}
+
+void addYears(struct tm *date, int y)
+{
+    return addMonths(date, 12*y);
+}
+
 const char* toString(AccessCheck ac)
 {
     switch (ac)
diff --git a/src/util.h b/src/util.h
index dfd9fad2..84869c8b 100644
--- a/src/util.h
+++ b/src/util.h
@@ -87,6 +87,8 @@ std::string strdatetimesec(double v);
 std::string strTimestampUTC(double v);
 void addMonths(struct tm* date, int m);
 double addMonths(double t, int m);
+void addYears(struct tm* date, int y);
+double addYears(double t, int y);
 
 bool stringFoundCaseIgnored(const std::string& haystack, const std::string& needle);
 
