diff --git a/api/main.py b/api/main.py index 7620e48..41b52c2 100644 --- a/api/main.py +++ b/api/main.py @@ -408,19 +408,26 @@ async def get_daily_aggregated_data( """Gibt täglich aggregierte Wetterdaten zurück (Tagesmittel mit Min/Max-Temperaturen)""" with conn.cursor() as cursor: cursor.execute(""" - SELECT + SELECT date_trunc('day', datetime) as datetime, AVG(temperature)::float as temperature, MIN(temperature)::float as min_temperature, MAX(temperature)::float as max_temperature, + (array_agg(datetime ORDER BY temperature ASC NULLS LAST))[1] as min_temperature_time, + (array_agg(datetime ORDER BY temperature DESC NULLS LAST))[1] as max_temperature_time, ROUND(AVG(humidity))::int as humidity, MIN(humidity)::int as min_humidity, MAX(humidity)::int as max_humidity, + (array_agg(datetime ORDER BY humidity ASC NULLS LAST))[1] as min_humidity_time, + (array_agg(datetime ORDER BY humidity DESC NULLS LAST))[1] as max_humidity_time, AVG(pressure)::float as pressure, MIN(pressure)::float as min_pressure, MAX(pressure)::float as max_pressure, + (array_agg(datetime ORDER BY pressure ASC NULLS LAST))[1] as min_pressure_time, + (array_agg(datetime ORDER BY pressure DESC NULLS LAST))[1] as max_pressure_time, AVG(wind_speed * 1.60934)::float as wind_speed, MAX(wind_gust * 1.60934)::float as wind_gust, + (array_agg(datetime ORDER BY wind_gust DESC NULLS LAST))[1] as max_wind_gust_time, AVG(wind_dir)::float as wind_dir, SUM(rain)::float as total_rain FROM weather_data @@ -441,19 +448,26 @@ async def get_daily_with_minmax_data( """Gibt täglich aggregierte Wetterdaten mit Min/Max-Temperaturen zurück""" with conn.cursor() as cursor: cursor.execute(""" - SELECT + SELECT date_trunc('day', datetime) as datetime, AVG(temperature)::float as temperature, MIN(temperature)::float as min_temperature, MAX(temperature)::float as max_temperature, + (array_agg(datetime ORDER BY temperature ASC NULLS LAST))[1] as min_temperature_time, + (array_agg(datetime ORDER BY temperature DESC NULLS LAST))[1] as max_temperature_time, ROUND(AVG(humidity))::int as humidity, MIN(humidity)::int as min_humidity, MAX(humidity)::int as max_humidity, + (array_agg(datetime ORDER BY humidity ASC NULLS LAST))[1] as min_humidity_time, + (array_agg(datetime ORDER BY humidity DESC NULLS LAST))[1] as max_humidity_time, AVG(pressure)::float as pressure, MIN(pressure)::float as min_pressure, MAX(pressure)::float as max_pressure, + (array_agg(datetime ORDER BY pressure ASC NULLS LAST))[1] as min_pressure_time, + (array_agg(datetime ORDER BY pressure DESC NULLS LAST))[1] as max_pressure_time, AVG(wind_speed * 1.60934)::float as wind_speed, MAX(wind_gust * 1.60934)::float as wind_gust, + (array_agg(datetime ORDER BY wind_gust DESC NULLS LAST))[1] as max_wind_gust_time, AVG(wind_dir)::float as wind_dir, SUM(rain)::float as total_rain FROM weather_data @@ -462,7 +476,7 @@ async def get_daily_with_minmax_data( ORDER BY datetime ASC """, (days,)) results = cursor.fetchall() - + return [dict(row) for row in results] @@ -561,19 +575,26 @@ async def get_daily_aggregated_range( with conn.cursor() as cursor: cursor.execute(""" - SELECT + SELECT date_trunc('day', datetime) as datetime, AVG(temperature)::float as temperature, MIN(temperature)::float as min_temperature, MAX(temperature)::float as max_temperature, + (array_agg(datetime ORDER BY temperature ASC NULLS LAST))[1] as min_temperature_time, + (array_agg(datetime ORDER BY temperature DESC NULLS LAST))[1] as max_temperature_time, ROUND(AVG(humidity))::int as humidity, MIN(humidity)::int as min_humidity, MAX(humidity)::int as max_humidity, + (array_agg(datetime ORDER BY humidity ASC NULLS LAST))[1] as min_humidity_time, + (array_agg(datetime ORDER BY humidity DESC NULLS LAST))[1] as max_humidity_time, AVG(pressure)::float as pressure, MIN(pressure)::float as min_pressure, MAX(pressure)::float as max_pressure, + (array_agg(datetime ORDER BY pressure ASC NULLS LAST))[1] as min_pressure_time, + (array_agg(datetime ORDER BY pressure DESC NULLS LAST))[1] as max_pressure_time, AVG(wind_speed * 1.60934)::float as wind_speed, MAX(wind_gust * 1.60934)::float as wind_gust, + (array_agg(datetime ORDER BY wind_gust DESC NULLS LAST))[1] as max_wind_gust_time, AVG(wind_dir)::float as wind_dir, SUM(rain)::float as total_rain FROM weather_data diff --git a/frontend/src/components/WeatherDashboard.jsx b/frontend/src/components/WeatherDashboard.jsx index 1636ab8..473a9ce 100644 --- a/frontend/src/components/WeatherDashboard.jsx +++ b/frontend/src/components/WeatherDashboard.jsx @@ -808,54 +808,56 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = ' } } - // Zeitformat basierend auf Zeitraum const isCustomRange = typeof timeRange === 'object' && timeRange.type === 'custom' const customDays = isCustomRange ? (timeRange.days || 1) : 0 - let timeFormat = 'dd.MM HH:mm' - - if (isCustomRange) { - timeFormat = customDays < 7 ? 'HH:mm' : 'dd.MM HH:mm' - } else { - timeFormat = timeRange === '24h' ? 'HH:mm' : 'dd.MM HH:mm' + const is24h = timeRange === '24h' || (isCustomRange && customDays < 7) + const timeFormat = is24h ? 'HH:mm' : 'dd.MM HH:mm' + + // Gibt die anzuzeigende Zeit zurück: bei aggregierten Daten das spezifische *_time-Feld, + // bei Rohdaten (24h) das datetime des Datenpunkts selbst. + const itemTime = (item, timeField) => { + if (!item) return null + const raw = item[timeField] ?? item.datetime + return format(new Date(raw), timeFormat, { locale: de }) } // Temperatur - const minTempItem = periodData.reduce((min, item) => + const minTempItem = periodData.reduce((min, item) => item.temperature != null && (min === null || item.temperature < min.temperature) ? item : min, null) - const maxTempItem = periodData.reduce((max, item) => + const maxTempItem = periodData.reduce((max, item) => item.temperature != null && (max === null || item.temperature > max.temperature) ? item : max, null) // Luftfeuchtigkeit - const minHumidityItem = periodData.reduce((min, item) => + const minHumidityItem = periodData.reduce((min, item) => item.humidity != null && (min === null || item.humidity < min.humidity) ? item : min, null) - const maxHumidityItem = periodData.reduce((max, item) => + const maxHumidityItem = periodData.reduce((max, item) => item.humidity != null && (max === null || item.humidity > max.humidity) ? item : max, null) // Luftdruck - const minPressureItem = periodData.reduce((min, item) => + const minPressureItem = periodData.reduce((min, item) => item.pressure != null && (min === null || item.pressure < min.pressure) ? item : min, null) - const maxPressureItem = periodData.reduce((max, item) => + const maxPressureItem = periodData.reduce((max, item) => item.pressure != null && (max === null || item.pressure > max.pressure) ? item : max, null) - // Windgeschwindigkeit - const maxWindGustItem = periodData.reduce((max, item) => + // Wind + const maxWindGustItem = periodData.reduce((max, item) => item.wind_gust != null && (max === null || item.wind_gust > max.wind_gust) ? item : max, null) return { minTemp: minTempItem?.temperature ?? null, maxTemp: maxTempItem?.temperature ?? null, - minTempTime: minTempItem ? format(new Date(minTempItem.datetime), timeFormat, { locale: de }) : null, - maxTempTime: maxTempItem ? format(new Date(maxTempItem.datetime), timeFormat, { locale: de }) : null, + minTempTime: itemTime(minTempItem, 'min_temperature_time'), + maxTempTime: itemTime(maxTempItem, 'max_temperature_time'), minHumidity: minHumidityItem?.humidity ?? null, maxHumidity: maxHumidityItem?.humidity ?? null, - minHumidityTime: minHumidityItem ? format(new Date(minHumidityItem.datetime), timeFormat, { locale: de }) : null, - maxHumidityTime: maxHumidityItem ? format(new Date(maxHumidityItem.datetime), timeFormat, { locale: de }) : null, + minHumidityTime: itemTime(minHumidityItem, 'min_humidity_time'), + maxHumidityTime: itemTime(maxHumidityItem, 'max_humidity_time'), minPressure: minPressureItem?.pressure ?? null, maxPressure: maxPressureItem?.pressure ?? null, - minPressureTime: minPressureItem ? format(new Date(minPressureItem.datetime), timeFormat, { locale: de }) : null, - maxPressureTime: maxPressureItem ? format(new Date(maxPressureItem.datetime), timeFormat, { locale: de }) : null, + minPressureTime: itemTime(minPressureItem, 'min_pressure_time'), + maxPressureTime: itemTime(maxPressureItem, 'max_pressure_time'), maxWindGust: maxWindGustItem?.wind_gust ?? null, - maxWindGustTime: maxWindGustItem ? format(new Date(maxWindGustItem.datetime), timeFormat, { locale: de }) : null + maxWindGustTime: itemTime(maxWindGustItem, 'max_wind_gust_time'), } }, [sortedData, timeRange])