Hoe kunnen we helpen?
How to automatically manage daylight saving time in the HMI using a macro?
In this post, we will show you how to automatically manage daylight saving time in the HMI using a macro. The time change was first applied in 1916. Since 2002, the time change has been carried out in a uniform manner in all the Member States of the European Union:
- the changeover to summer time takes place on the night of the last Saturday in March
- the changeover to winter time takes place on the night of the last Saturday in October

As a reminder, the EU countries are currently divided into three time zones:
- Western Europe (GMT): Ireland and Portugal
- Central Europe (GMT+1): Austria, Belgium, Croatia, Czech Republic, Denmark, France, Germany, Hungary, Italy, Luxembourg, Malta, Netherlands, Poland, Slovakia, Slovenia, Spain and Sweden
- Eastern Europe (GMT+2): Bulgaria, Cyprus, Estonia, Finland, Greece, Latvia, Lithuania and Romania.
With HMI-Tool

In the Macro Editor, add a new macro and copy it.
#include "MacroInit.h"
// Returns the day-of-month of the last Sunday of a given month/year
// Uses the Tomohiko Sakamoto-inspired method (no division by 7 needed)
int LastSundayOfMonth(int month, int year)
{
// Day of week of the last day of the month (0=Sunday ... 6=Saturday)
// Zeller-like formula for day-of-week of day 1, then offset to last day
int y = year;
int m = month;
int daysInMonth;
switch(m)
{
case 1: daysInMonth = 31; break;
case 2:
if ((y % 400 == 0) || (y % 4 == 0 && y % 100 != 0))
daysInMonth = 29;
else
daysInMonth = 28;
break;
case 3: daysInMonth = 31; break;
case 4: daysInMonth = 30; break;
case 5: daysInMonth = 31; break;
case 6: daysInMonth = 30; break;
case 7: daysInMonth = 31; break;
case 8: daysInMonth = 31; break;
case 9: daysInMonth = 30; break;
case 10: daysInMonth = 31; break;
case 11: daysInMonth = 30; break;
case 12: daysInMonth = 31; break;
default: daysInMonth = 30; break;
}
// Compute day-of-week of the last day of the month
// Using Zeller's formula (0=Sunday, 1=Monday ... 6=Saturday)
if (m < 3) { m += 12; y -= 1; }
int k = y % 100;
int j = y / 100;
int dow = (daysInMonth + (13*(m+1))/5 + k + k/4 + j/4 - 2*j) % 7;
// Zeller returns: 0=Saturday, 1=Sunday, 2=Monday ... 6=Friday
// Normalize to: 0=Sunday, 1=Monday ... 6=Saturday
dow = (dow + 6) % 7;
// Subtract offset to reach last Sunday (dow==0)
return daysInMonth - dow;
}
void Macro_main(IN *p)
{
MarcoInit
// Automatic Daylight Saving Time (DST) management
// <!> This script must be called every minute
// DST start : last Sunday of March - 02:00 -> 03:00 (clock forward +1h)
// DST end : last Sunday of October - 03:00 -> 02:00 (clock back -1h)
// LocalBit[50000]: 0 = summer time, 1 = winter time (backed up on power failure)
// Catchup window: up to 6 days after the DST Sunday (HMI was powered off)
int minute = BCD2BIN(LocalWord[60001]); // Current minute
int hour = BCD2BIN(LocalWord[60002]); // Current hour
int day = BCD2BIN(LocalWord[60003]); // Day of month
int month = BCD2BIN(LocalWord[60004]); // Month
int year = BCD2BIN(LocalWord[60005]); // Year (needed for LastSundayOfMonth)
int dayOfWeek = BCD2BIN(LocalWord[60006]); // Monday=1 ... Sunday=7
// --- DST START : last Sunday of March at 02:00 -> 03:00 ---
// Window: from Sunday at 02:00 until the following Saturday at 23:59 (6 days catchup)
int lastSunMarch = LastSundayOfMonth(3, year);
int daysSinceDSTStart = day - lastSunMarch; // Positive if we are past the last Sunday
int dstStartWindow = (daysSinceDSTStart == 0 && hour >= 2) || // Sunday from 02:00
(daysSinceDSTStart >= 1 && daysSinceDSTStart <= 6); // Mon to Sat catchup
if ((LocalBit[50000] == 1) &&
(month == 3) &&
dstStartWindow)
{
LocalWord[60002] = BIN2BCD(hour + 1); // Shift clock forward by 1 hour
LocalBit[50000] = 0; // Flag: now summer time
}
// --- DST END : last Sunday of October at 03:00 -> 02:00 ---
// Window: from Sunday at 03:00 until the following Saturday at 23:59 (6 days catchup)
int lastSunOctober = LastSundayOfMonth(10, year);
int daysSinceDSTEnd = day - lastSunOctober;
int dstEndWindow = (daysSinceDSTEnd == 0 && hour >= 3) || // Sunday from 03:00
(daysSinceDSTEnd >= 1 && daysSinceDSTEnd <= 6); // Mon to Sat catchup
if ((LocalBit[50000] == 0) &&
(month == 10) &&
dstEndWindow)
{
LocalWord[60002] = BIN2BCD(hour - 1); // Shift clock back by 1 hour
LocalBit[50000] = 1; // Flag: now winter time
}
}
Add the macro in “global Macro” list And set its execution frequency to 60000 ms (1 minute) to update the clock every minute.

How it works
The program runs every minute and reads the current time (minute, hour, day, month, year, weekday) from registers.
All time values are stored in BCD format, so they are first converted to decimal.
A helper function computes the number of days in the current month, including leap years.
To detect the last Sunday of the month, the code checks: dayOfWeek == 7 (Sunday) and day + 7 > daysInMonth.
If it is the last Sunday of March at exactly 03:00, the clock is advanced to 04:00 (Daylight Saving Time).
A flag bit (LocalBit[65535]) is set to indicate summer time.
If it is the last Sunday of October at exactly 03:00, the clock is moved back to 02:00 (Winter Time).
The flag bit is switched to indicate winter time, preventing repeated corrections.
This avoids infinite loops where the same hour would be processed multiple times.
The system therefore keeps local time synchronized with official DST rules automatically.
You can replace LB65535 by LB51999 for backup the value (HMI register types: LB, LW, RWI and retentive/save register)
See also How to set and synchronize the ACE PLC clock with the HMI using a macro