diff --git a/sql/init_data.h2.sql b/sql/init_data.h2.sql
index 61324b1e4182b74cfa27829e47d8a5e9a3d29c70..af14566f93648db3c69da1b95a1add75fce6f85e 100644
--- a/sql/init_data.h2.sql
+++ b/sql/init_data.h2.sql
@@ -55,11 +55,13 @@ INSERT INTO cellpra (cell, pra, ratio)
 -- period
 CREATE TEMPORARY TABLE IF NOT EXISTS tmp_period (
     code VARCHAR,
-    phase VARCHAR
+    phase VARCHAR,
+    firstday VARCHAR,
+    lastday VARCHAR
 );
-INSERT INTO tmp_period (code, phase) SELECT * FROM CSVREAD('../sql/periods.csv');
-INSERT INTO period (code, name, phase)
-    SELECT t.code, k.id, t.phase
+INSERT INTO tmp_period (code, phase, firstday, lastday) SELECT * FROM CSVREAD('../sql/periods.csv');
+INSERT INTO period (code, name, phase, firstday, lastday)
+    SELECT t.code, k.id, t.phase, t.firstday, t.lastday
     FROM tmp_period AS t
     JOIN i18nkey AS k ON k.string=t.code;
 
@@ -90,7 +92,7 @@ CREATE TEMPORARY TABLE IF NOT EXISTS tmp_dailyvalue (
     comparedvalue DOUBLE PRECISION
 );
 INSERT INTO tmp_dailyvalue (indicator, period, cell, date, computedvalue, comparedvalue)
-	SELECT * FROM CSVREAD('../sql/dailyvalues.csv');
+    SELECT * FROM CSVREAD('../sql/dailyvalues.csv');
 INSERT INTO dailyvalue (indicator, cell, date, computedvalue, comparedvalue)
     SELECT i.id, t.cell, t.date, t.computedvalue, t.comparedvalue
     FROM tmp_dailyvalue AS t
@@ -107,7 +109,7 @@ CREATE TEMPORARY TABLE IF NOT EXISTS tmp_normalvalue (
     computedvalue DOUBLE PRECISION
 );
 INSERT INTO tmp_normalvalue (indicator, period, cell, doy, computedvalue)
-	SELECT * FROM CSVREAD('../sql/normalvalues.csv');
+    SELECT * FROM CSVREAD('../sql/normalvalues.csv');
 INSERT INTO normalvalue (indicator, cell, doy, computedvalue)
     SELECT i.id, t.cell, t.doy, t.computedvalue
     FROM tmp_normalvalue AS t
@@ -117,5 +119,5 @@ INSERT INTO normalvalue (indicator, cell, doy, computedvalue)
 
 -- simulation
 INSERT INTO simulation (date, simulationid, started, ended) VALUES
-	('2024-02-19', 1, '2024-02-20 12:00:00', '2024-02-20 12:30:00'),
-	('2024-02-20', 2, '2024-02-21 13:00:00', NULL);
\ No newline at end of file
+    ('2024-02-19', 1, '2024-02-20 12:00:00', '2024-02-20 12:30:00'),
+    ('2024-02-20', 2, '2024-02-21 13:00:00', NULL);
diff --git a/sql/init_data.postgresql.sql b/sql/init_data.postgresql.sql
index e5cd1990dd34469d2ae28130944dba91b777a768..84c10d4d57656e8742dfe0afa6f071bb3f71cf5c 100644
--- a/sql/init_data.postgresql.sql
+++ b/sql/init_data.postgresql.sql
@@ -63,11 +63,13 @@ INSERT INTO cell (id, lat, lon, lat1, lon1, lat2, lon2, lat3, lon3, lat4, lon4,
 -- period
 CREATE TEMPORARY TABLE IF NOT EXISTS tmp_period (
     code VARCHAR,
-    phase VARCHAR
+    phase VARCHAR,
+    firstday VARCHAR,
+    lastday VARCHAR
 );
-\COPY tmp_period (code, phase) FROM periods.csv WITH DELIMITER ',' HEADER CSV;
-INSERT INTO period (code, name, phase)
-    SELECT t.code, k.id, t.phase
+\COPY tmp_period (code, phase, firstday, lastday) FROM periods.csv WITH DELIMITER ',' HEADER CSV;
+INSERT INTO period (code, name, phase, firstday, lastday)
+    SELECT t.code, k.id, t.phase, t.firstday, t.lastday
     FROM tmp_period AS t
     JOIN i18nkey AS k ON k.string=t.code;
 
diff --git a/sql/migration.sql b/sql/migration.sql
index 83d6144c921cb3e3255775bce4ad9abf11071c8a..e4094c63ad430e8d20249848e7578c0c34474d32 100644
--- a/sql/migration.sql
+++ b/sql/migration.sql
@@ -36,21 +36,21 @@ BEGIN
   SELECT schemaversion() INTO schemaversion;
   RAISE INFO '% Apply migrations after %...', TIMEOFDAY(), schemaversion;
   FOR routine IN
-	SELECT
-	  routine_name,
-	  substring(routine_name, 8) AS migration_version
-	FROM information_schema.routines
-	WHERE routine_type = 'FUNCTION' AND
-	  routine_name LIKE 'upgrade20%' AND
-	  substring(routine_name, 8) NOT IN (SELECT version FROM dbmigration) AND
-	  substring(routine_name, 8) > schemaversion
-	ORDER BY routine_name
+    SELECT
+      routine_name,
+      substring(routine_name, 8) AS migration_version
+    FROM information_schema.routines
+    WHERE routine_type = 'FUNCTION' AND
+      routine_name LIKE 'upgrade20%' AND
+      substring(routine_name, 8) NOT IN (SELECT version FROM dbmigration) AND
+      substring(routine_name, 8) > schemaversion
+    ORDER BY routine_name
   LOOP
-	RAISE INFO '% %() start', TIMEOFDAY(), routine.routine_name;
-	EXECUTE format('SELECT %I()', routine.routine_name);
-	INSERT INTO dbmigration (version) values(routine.migration_version);
-	RAISE INFO '% %() end', TIMEOFDAY(), routine.routine_name;
-	applied := applied + 1;
+    RAISE INFO '% %() start', TIMEOFDAY(), routine.routine_name;
+    EXECUTE format('SELECT %I()', routine.routine_name);
+    INSERT INTO dbmigration (version) values(routine.migration_version);
+    RAISE INFO '% %() end', TIMEOFDAY(), routine.routine_name;
+    applied := applied + 1;
   END LOOP;
   RAISE INFO '% % migrations were applied', TIMEOFDAY(), applied;
   RETURN applied;
@@ -90,19 +90,19 @@ COMMENT ON FUNCTION drop_applied_migration_functions() IS 'Purge database from a
 ---
 CREATE OR REPLACE FUNCTION upgrade20231023() RETURNS boolean AS $BODY$
 BEGIN
-	ALTER TABLE indicator DROP COLUMN colorsequence;
-	DROP TABLE colorsequence;
-	ALTER TABLE indicator ADD COLUMN colorsequencename VARCHAR;
-	ALTER TABLE indicator ADD COLUMN nbofclasses INTEGER;
-	CREATE TYPE QUANTILETYPE AS ENUM('CENTILES_05', 'QUANTILES', 'DECILES', 'QUINTILES', 'QUARTILES');
-	ALTER TABLE indicator ADD COLUMN quantiletype QUANTILETYPE;
-	UPDATE indicator SET quantiletype='QUINTILES';
-	UPDATE indicator SET colorsequencename='Precipitation' WHERE code='rainsum';
-	UPDATE indicator SET colorsequencename='Blues' WHERE code='frostdaystmin';
-	UPDATE indicator SET colorsequencename='Temperature' WHERE code IN ('mint', 'meant', 'maxt');
-	UPDATE indicator SET colorsequencename='YlOrRd' WHERE code IN ('hdaystmax', 'hdaystmax1');
-	ALTER TABLE indicator ADD CONSTRAINT "CK_indicator_colorsequence" CHECK (nbofclasses IS NOT NULL OR quantiletype IS NOT NULL);
-	RETURN true;
+    ALTER TABLE indicator DROP COLUMN colorsequence;
+    DROP TABLE colorsequence;
+    ALTER TABLE indicator ADD COLUMN colorsequencename VARCHAR;
+    ALTER TABLE indicator ADD COLUMN nbofclasses INTEGER;
+    CREATE TYPE QUANTILETYPE AS ENUM('CENTILES_05', 'QUANTILES', 'DECILES', 'QUINTILES', 'QUARTILES');
+    ALTER TABLE indicator ADD COLUMN quantiletype QUANTILETYPE;
+    UPDATE indicator SET quantiletype='QUINTILES';
+    UPDATE indicator SET colorsequencename='Precipitation' WHERE code='rainsum';
+    UPDATE indicator SET colorsequencename='Blues' WHERE code='frostdaystmin';
+    UPDATE indicator SET colorsequencename='Temperature' WHERE code IN ('mint', 'meant', 'maxt');
+    UPDATE indicator SET colorsequencename='YlOrRd' WHERE code IN ('hdaystmax', 'hdaystmax1');
+    ALTER TABLE indicator ADD CONSTRAINT "CK_indicator_colorsequence" CHECK (nbofclasses IS NOT NULL OR quantiletype IS NOT NULL);
+    RETURN true;
 END
 $BODY$
 language plpgsql;
@@ -112,23 +112,23 @@ language plpgsql;
 ---
 CREATE OR REPLACE FUNCTION upgrade20231030() RETURNS boolean AS $BODY$
 BEGIN
-	ALTER TABLE "indicator" ALTER COLUMN quantiletype TYPE VARCHAR USING QUANTILETYPE::VARCHAR;
-	DROP TYPE QUANTILETYPE;
-	CREATE TYPE QUANTILETYPE AS ENUM('CENTILES_05', 'QUANTILES', 'DECILES', 'QUINTILES', 'QUARTILES', 'SEXTILES');
-	ALTER TABLE "indicator" ALTER COLUMN quantiletype TYPE QUANTILETYPE USING quantiletype::quantiletype;
-	UPDATE indicator SET quantiletype='SEXTILES';
-	--- #12
-	CREATE TYPE AGGREGATIONTYPE AS ENUM('AVG', 'MAX');
-	ALTER TABLE "indicator" ADD COLUMN aggregationtype AGGREGATIONTYPE;
-	UPDATE indicator SET unit='mm' WHERE code IN ('rainsum');
-	UPDATE indicator SET unit='j' WHERE code IN ('frostdaystmin', 'hdaystmax', 'hdaystmax1');
-	UPDATE indicator SET unit='°C' WHERE code IN ('maxt', 'meant', 'mint');
-	UPDATE indicator SET aggregationtype='MAX' WHERE code IN ('frostdaystmin', 'hdaystmax', 'hdaystmax1', 'rainsum');
-	UPDATE indicator SET aggregationtype='AVG' WHERE code IN ('maxt', 'meant', 'mint');
-	ALTER TABLE "indicator" ALTER COLUMN aggregationtype SET NOT NULL;
-	--- #8
-	UPDATE indicator SET colorsequencename='TemperatureReversed' WHERE code IN ('mint', 'meant', 'maxt');
-	RETURN true;
+    ALTER TABLE "indicator" ALTER COLUMN quantiletype TYPE VARCHAR USING QUANTILETYPE::VARCHAR;
+    DROP TYPE QUANTILETYPE;
+    CREATE TYPE QUANTILETYPE AS ENUM('CENTILES_05', 'QUANTILES', 'DECILES', 'QUINTILES', 'QUARTILES', 'SEXTILES');
+    ALTER TABLE "indicator" ALTER COLUMN quantiletype TYPE QUANTILETYPE USING quantiletype::quantiletype;
+    UPDATE indicator SET quantiletype='SEXTILES';
+    --- #12
+    CREATE TYPE AGGREGATIONTYPE AS ENUM('AVG', 'MAX');
+    ALTER TABLE "indicator" ADD COLUMN aggregationtype AGGREGATIONTYPE;
+    UPDATE indicator SET unit='mm' WHERE code IN ('rainsum');
+    UPDATE indicator SET unit='j' WHERE code IN ('frostdaystmin', 'hdaystmax', 'hdaystmax1');
+    UPDATE indicator SET unit='°C' WHERE code IN ('maxt', 'meant', 'mint');
+    UPDATE indicator SET aggregationtype='MAX' WHERE code IN ('frostdaystmin', 'hdaystmax', 'hdaystmax1', 'rainsum');
+    UPDATE indicator SET aggregationtype='AVG' WHERE code IN ('maxt', 'meant', 'mint');
+    ALTER TABLE "indicator" ALTER COLUMN aggregationtype SET NOT NULL;
+    --- #8
+    UPDATE indicator SET colorsequencename='TemperatureReversed' WHERE code IN ('mint', 'meant', 'maxt');
+    RETURN true;
 END
 $BODY$
 language plpgsql;
@@ -138,8 +138,8 @@ language plpgsql;
 --
 CREATE OR REPLACE FUNCTION upgrade20231215() RETURNS boolean AS $BODY$
 BEGIN
-	INSERT INTO department (id, "name", region) VALUES(75, '75 - Paris', 75);
-	RETURN true;
+    INSERT INTO department (id, "name", region) VALUES(75, '75 - Paris', 75);
+    RETURN true;
 END
 $BODY$
 language plpgsql;
@@ -149,9 +149,9 @@ language plpgsql;
 --
 CREATE OR REPLACE FUNCTION upgrade20240220() RETURNS boolean AS $BODY$
 BEGIN
-	INSERT INTO simulation (date, simulationid, started, ended) VALUES
-		('2024-02-19', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
-	RETURN true;
+    INSERT INTO simulation (date, simulationid, started, ended) VALUES
+        ('2024-02-19', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
+    RETURN true;
 END
 $BODY$
 language plpgsql;
@@ -161,10 +161,27 @@ language plpgsql;
 --
 CREATE OR REPLACE FUNCTION upgrade20240306() RETURNS boolean AS $BODY$
 BEGIN
-	CREATE INDEX IF NOT EXISTS "IX_dailyvalue" ON dailyvalue (date, indicator);
-	ALTER TABLE indicator DROP COLUMN aggregationtype;
-	DROP TYPE AGGREGATIONTYPE;
-	RETURN true;
+    CREATE INDEX IF NOT EXISTS "IX_dailyvalue" ON dailyvalue USING btree (date, indicator);
+    ALTER TABLE indicator DROP COLUMN aggregationtype;
+    DROP TYPE AGGREGATIONTYPE;
+    RETURN true;
+END
+$BODY$
+language plpgsql;
+
+--
+-- #20
+--
+CREATE OR REPLACE FUNCTION upgrade20240313() RETURNS boolean AS $BODY$
+BEGIN
+    ALTER TABLE period ADD COLUMN firstday VARCHAR(10);
+    ALTER TABLE period ADD COLUMN lastday VARCHAR(10);
+    UPDATE period SET firstday='YYYY-01-01', lastday='YYYY-12-31' WHERE code='year';
+    UPDATE period SET firstday='YYYY-04-01', lastday='YYYY-10-15' WHERE code='summer';
+    UPDATE period SET firstday='XXXX-10-31', lastday='YYYY-08-31' WHERE code='winter';
+    ALTER TABLE period ALTER COLUMN firstday SET NOT NULL;
+    ALTER TABLE period ALTER COLUMN lastday SET NOT NULL;
+    RETURN true;
 END
 $BODY$
 language plpgsql;
diff --git a/sql/periods.csv b/sql/periods.csv
index 97291a0eb8fa20d846d1706b5b3694f5bd6c2d0b..099bcccacdbb8af9f3722ad1928dddb43c8019d2 100644
--- a/sql/periods.csv
+++ b/sql/periods.csv
@@ -1,4 +1,4 @@
-code,phase
-year,s2s8
-summer,s4s7
-winter,s1s6
\ No newline at end of file
+code,phase,firstday,lastday
+year,s2s8,YYYY-01-01,YYYY-12-31
+summer,s4s7,YYYY-04-01,YYYY-10-15
+winter,s1s6,XXXX-10-31,YYYY-08-31
\ No newline at end of file
diff --git a/sql/schema.tables.sql b/sql/schema.tables.sql
index 7d7074a10de1aa2edab7cf04faa6ab500deebf33..169877dae6dc4c2931ecee992b5dfe42fb4f309f 100644
--- a/sql/schema.tables.sql
+++ b/sql/schema.tables.sql
@@ -132,6 +132,8 @@ CREATE TABLE IF NOT EXISTS period (
     code VARCHAR NOT NULL,
     name INTEGER NOT NULL,
     phase VARCHAR NOT NULL,
+    firstday VARCHAR(10) NOT NULL,
+    lastday VARCHAR(10) NOT NULL,
     created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
     CONSTRAINT "PK_period" PRIMARY KEY (id),
     CONSTRAINT "FK_period_i18n" FOREIGN KEY (name) REFERENCES i18n (id),
@@ -139,6 +141,8 @@ CREATE TABLE IF NOT EXISTS period (
 );
 COMMENT ON TABLE period IS 'Period when the indicator is computed.';
 COMMENT ON COLUMN period.phase IS 'Related phase name from GETARI file.';
+COMMENT ON COLUMN period.firstday IS 'The first day of the agroclimatic phase.';
+COMMENT ON COLUMN period.lastday IS 'The last day of the agroclimatic phase.';
 
 CREATE TABLE IF NOT EXISTS indicator (
     id SERIAL,
diff --git a/sql/test_sql_on_postgresql.sh b/sql/test_sql_on_postgresql.sh
new file mode 100755
index 0000000000000000000000000000000000000000..a1a38023f0c9f449f235026c6d1b59d64b1f1be0
--- /dev/null
+++ b/sql/test_sql_on_postgresql.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+cd $(dirname $0)
+dropdb agrometinfotmp
+createdb agrometinfotmp
+psql agrometinfotmp -1 -f schema.types.postgresql.sql 
+psql agrometinfotmp -1 -f schema.tables.sql 
+psql agrometinfotmp -1 -f init_data.postgresql.sql 
+sleep 1
+dropdb agrometinfotmp
+echo "done"
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Period.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/Period.java
index 2f4a63efbcd5e27b730f29ebbd029a601f573115..02921226389df685cc6d713607be670c4a438c2c 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/model/Period.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/Period.java
@@ -36,6 +36,16 @@ public class Period {
      */
     @Column(name = "code")
     private String code;
+    /**
+     * First day of agroclimatic phase.
+     */
+    @Column(name = "firstday")
+    private String firstDay;
+    /**
+     * Last day of agroclimatic phase.
+     */
+    @Column(name = "lastday")
+    private String lastDay;
     /**
      * Defined to use in @JoinTable.
      */
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/IndicatorResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/IndicatorResource.java
index 465e6d6db6c951fb38c6edefb550277b2b4c5d21..907b1d21874e189cfd9ea3d2da758f159560d22a 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/IndicatorResource.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/IndicatorResource.java
@@ -3,7 +3,6 @@ package fr.agrometinfo.www.server.rs;
 import static fr.agrometinfo.www.server.util.GeometryUtils.toFeature;
 
 import java.time.LocalDate;
-import java.time.ZoneId;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
@@ -62,6 +61,19 @@ import lombok.extern.log4j.Log4j2;
 @RequestScoped
 public class IndicatorResource implements IndicatorService {
 
+    /**
+     * Get the date related to the year.
+     *
+     * @param year year
+     * @param dateTemplate date template with YYYY for year and XXXX for previous year
+     * @return date from template.
+     */
+    private static LocalDate getDate(final Integer year, final String dateTemplate) {
+        return LocalDate.parse(dateTemplate//
+                .replace("YYYY", String.valueOf(year))//
+                .replace("XXXX", String.valueOf(year - 1)));
+    }
+
     private static String getTranslation(final Map<String, String> names, final Locale locale) {
         final var locales = List.of(locale, Locale.FRENCH, Locale.ENGLISH);
         for (final Locale l : locales) {
@@ -304,6 +316,8 @@ public class IndicatorResource implements IndicatorService {
                     .build());
         }
 
+        final var firstDay = getDate(year, indicator.getPeriod().getFirstDay());
+        final var lastDay = getDate(year, indicator.getPeriod().getLastDay());
         final var date = praDailyValueDao.findLastDate(indicator, year);
         final Double averageValue;
         final Double comparedValue;
@@ -311,7 +325,6 @@ public class IndicatorResource implements IndicatorService {
         // By default, all key-value pairs in TreeMap are sorted in their natural
         // ordering.
         final Map<Date, Float> dailyValues = new TreeMap<>();
-        final LocalDate yearAgo = date.minusYears(1);
         final SimpleFeature parentFeature;
         final String featureName;
         if (level == FeatureLevel.REGION) {
@@ -332,12 +345,12 @@ public class IndicatorResource implements IndicatorService {
                 featureName = null;
                 averageValue = praDailyValueDao.findAverageComputedValue(indicator, date);
                 comparedValue = praDailyValueDao.findAverageComparedValue(indicator, date);
-                tmpDailyValues = praDailyValueDao.findDailyValues(indicator, yearAgo, date);
+                tmpDailyValues = praDailyValueDao.findDailyValues(indicator, firstDay, lastDay);
                 parentFeature = null;
             } else {
                 averageValue = praDailyValueDao.findAverageComputedValue(indicator, date, regionId);
                 comparedValue = praDailyValueDao.findAverageComparedValue(indicator, date, regionId);
-                tmpDailyValues = praDailyValueDao.findDailyValues(indicator, yearAgo, date, region);
+                tmpDailyValues = praDailyValueDao.findDailyValues(indicator, firstDay, lastDay, region);
                 featureName = region.getName();
                 parentFeature = null;
             }
@@ -346,7 +359,7 @@ public class IndicatorResource implements IndicatorService {
             final PraDailyValue value = praDailyValueDao.find(indicator, date, pra);
             averageValue = value.getComputedValue().doubleValue();
             comparedValue = value.getComparedValue().doubleValue();
-            tmpDailyValues = praDailyValueDao.findDailyValues(indicator, yearAgo, date, pra);
+            tmpDailyValues = praDailyValueDao.findDailyValues(indicator, firstDay, lastDay, pra);
             featureName = pra.getName();
             parentFeature = new SimpleFeature();
             parentFeature.setId(String.valueOf(pra.getDepartment().getRegion().getId()));
@@ -371,7 +384,7 @@ public class IndicatorResource implements IndicatorService {
         if (comparedValue != null) {
             dto.setComparedValue(comparedValue.floatValue());
         }
-        dto.setDate(Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant()));
+        dto.setDate(DateUtils.toDate(date));
         dto.setDailyValues(dailyValues);
         if (featureName != null) {
             dto.setFeatureName(featureName);