@@ -191,7 +191,7 @@ impl ContextBuilder {
191191 }
192192
193193 pub fn with_daily_forecast_data ( & mut self , daily_forecast_data : Vec < DailyEntry > ) -> & mut Self {
194- // The date returned by Bom api is x:14 utc , which translates to x+10:00 AEST time,
194+ // The date returned by Bom api is UTC, for example x:14 UTC , which translates to x:14 +10:00 AEST time,
195195 // so we have to do some conversion
196196 let local_date_truncated = Local :: now ( )
197197 . with_hour ( 0 )
@@ -310,11 +310,12 @@ impl ContextBuilder {
310310 }
311311 }
312312
313+ // Extrusion Pattern: force everything through one function until it resembles spaghetti
313314 pub fn with_hourly_forecast_data (
314315 & mut self ,
315316 hourly_forecast_data : Vec < HourlyForecast > ,
316317 ) -> & mut Self {
317- let ( forecast_window_start , forecast_window_end ) = match Self :: find_forecast_window (
318+ let ( utc_forecast_window_start , utc_forecast_window_end ) = match Self :: find_forecast_window (
318319 & hourly_forecast_data,
319320 ) {
320321 Some ( ( start, end) ) => ( start, end) ,
@@ -325,8 +326,30 @@ impl ContextBuilder {
325326 }
326327 } ;
327328
328- println ! ( "24h forecast window start : {:?}" , forecast_window_start) ;
329- println ! ( "24h forecast window end : {:?}" , forecast_window_end) ;
329+ println ! (
330+ "24h UTC forecast window: start = {:?}, end = {:?}" ,
331+ utc_forecast_window_start, utc_forecast_window_end
332+ ) ;
333+
334+ let local_forecast_window_start: DateTime < Local > =
335+ utc_forecast_window_start. with_timezone ( & Local ) ;
336+ let local_forecast_window_end: DateTime < Local > =
337+ utc_forecast_window_end. with_timezone ( & Local ) ;
338+ let day_end = local_forecast_window_start
339+ . with_hour ( 0 )
340+ . unwrap ( )
341+ . with_minute ( 0 )
342+ . unwrap ( )
343+ . with_second ( 0 )
344+ . unwrap ( )
345+ + chrono:: Duration :: days ( 1 ) ;
346+
347+ println ! (
348+ "Local forecast window: start = {:?}, end = {:?}" ,
349+ local_forecast_window_start, local_forecast_window_end
350+ ) ;
351+
352+ // println!("Day end: {:?}", day_end);
330353
331354 let mut graph = HourlyForecastGraph {
332355 x_axis_always_at_min : CONFIG . render_options . x_axis_always_at_min ,
@@ -337,53 +360,22 @@ impl ContextBuilder {
337360 Self :: populate_graph_data (
338361 self ,
339362 & hourly_forecast_data,
340- forecast_window_start ,
341- forecast_window_end ,
363+ local_forecast_window_start ,
364+ local_forecast_window_end ,
342365 & mut graph,
343366 ) ;
344367
345368 let svg_result = graph. draw_graph ( ) . unwrap ( ) ;
346369 let ( temp_curve_data, feel_like_curve_data, rain_curve_data) =
347370 Self :: extract_curve_data ( & svg_result) ;
348-
349- let day_start = forecast_window_start
350- . with_hour ( 0 )
351- . unwrap ( )
352- . with_minute ( 0 )
353- . unwrap ( )
354- . with_second ( 0 )
355- . unwrap ( ) ;
356- let day_end = day_start + chrono:: Duration :: days ( 1 ) ;
357-
358- // println!("day_start: {:?}", day_start);
359- // println!("day_end: {:?}", day_end);
360-
361371 self . context . graph_height = graph. height . to_string ( ) ;
362372 self . context . graph_width = graph. width . to_string ( ) ;
363373 self . context . actual_temp_curve_data = temp_curve_data;
364374 self . context . feel_like_curve_data = feel_like_curve_data;
365375 self . context . rain_curve_data = rain_curve_data;
366376
367- Self :: set_max_values (
368- self ,
369- & hourly_forecast_data,
370- forecast_window_start,
371- day_end,
372- forecast_window_end,
373- ) ;
374-
375- self . context . total_rain_today = ( get_total_between_dates (
376- & hourly_forecast_data,
377- & forecast_window_start,
378- & forecast_window_end,
379- |item : & HourlyForecast | item. rain . calculate_median_rain ( ) ,
380- |item| & item. time ,
381- ) )
382- . to_string ( ) ;
383-
384- let forecast_window_start_local = forecast_window_start. with_timezone ( & chrono:: Local ) ;
385377 let axis_data_path =
386- graph. create_axis_with_labels ( forecast_window_start_local . hour ( ) as f32 ) ;
378+ graph. create_axis_with_labels ( local_forecast_window_start . hour ( ) as f32 ) ;
387379
388380 self . context . x_axis_path = axis_data_path. x_axis_path ;
389381 self . context . y_left_axis_path = axis_data_path. y_left_axis_path ;
@@ -394,6 +386,24 @@ impl ContextBuilder {
394386 self . context . x_axis_guideline_path = axis_data_path. x_axis_guideline_path ;
395387
396388 self . context . uv_gradient = graph. draw_uv_gradient_over_time ( ) ;
389+
390+ Self :: set_max_values_for_table (
391+ self ,
392+ & hourly_forecast_data,
393+ local_forecast_window_start,
394+ day_end,
395+ local_forecast_window_end,
396+ ) ;
397+
398+ self . context . total_rain_today = ( get_total_between_dates (
399+ & hourly_forecast_data,
400+ & local_forecast_window_start,
401+ & local_forecast_window_end,
402+ |item : & HourlyForecast | item. rain . calculate_median_rain ( ) ,
403+ |item| item. time . with_timezone ( & Local ) ,
404+ ) )
405+ . to_string ( ) ;
406+
397407 self
398408 }
399409
@@ -407,7 +417,7 @@ impl ContextBuilder {
407417 . unwrap ( )
408418 . with_nanosecond ( 0 )
409419 . unwrap ( ) ;
410- println ! ( "Current UTC date : {:?}" , current_date) ;
420+ println ! ( "Current time ( UTC, to the hour) : {:?}" , current_date) ;
411421
412422 let first_date = hourly_forecast_data. iter ( ) . find_map ( |forecast| {
413423 if forecast. time >= current_date {
@@ -425,11 +435,25 @@ impl ContextBuilder {
425435 }
426436 }
427437
438+ fn extract_curve_data ( svg_result : & [ GraphDataPath ] ) -> ( String , String , String ) {
439+ svg_result. iter ( ) . fold (
440+ ( String :: new ( ) , String :: new ( ) , String :: new ( ) ) ,
441+ |( mut temp_acc, mut feel_like_acc, mut rain_acc) , path| {
442+ match path {
443+ GraphDataPath :: Temp ( data) => temp_acc. push_str ( data) ,
444+ GraphDataPath :: TempFeelLike ( data) => feel_like_acc. push_str ( data) ,
445+ GraphDataPath :: Rain ( data) => rain_acc. push_str ( data) ,
446+ }
447+ ( temp_acc, feel_like_acc, rain_acc)
448+ } ,
449+ )
450+ }
451+
428452 fn populate_graph_data (
429453 & mut self ,
430454 hourly_forecast_data : & [ HourlyForecast ] ,
431- forecast_window_start : chrono:: DateTime < Utc > ,
432- forecast_window_end : chrono:: DateTime < Utc > ,
455+ forecast_window_start : chrono:: DateTime < Local > ,
456+ forecast_window_end : chrono:: DateTime < Local > ,
433457 graph : & mut HourlyForecastGraph ,
434458 ) {
435459 let mut x = 0 ;
@@ -441,6 +465,7 @@ impl ContextBuilder {
441465 . for_each ( |forecast| {
442466 if x == 0 {
443467 self . with_current_hour_data ( forecast) ;
468+ self . set_now_values_for_table ( forecast)
444469 } else if x >= 24 {
445470 eprintln ! (
446471 "Warning: More than 24 hours of hourly forecast data, this should not happen"
@@ -466,105 +491,94 @@ impl ContextBuilder {
466491 self . context . current_hour_actual_temp = current_hour. temp . to_string ( ) ;
467492 self . context . current_hour_weather_icon = current_hour. get_icon_path ( ) ;
468493 self . context . current_hour_feels_like = current_hour. temp_feels_like . to_string ( ) ;
469- self . context . current_hour_wind_speed = current_hour. wind . get_speed ( ) . to_string ( ) ;
470- self . context . current_hour_wind_icon = current_hour. wind . get_icon_path ( ) ;
471- self . context . current_hour_uv_index = current_hour. uv . 0 . to_string ( ) ;
472- self . context . current_hour_uv_index_icon = current_hour. uv . get_icon_path ( ) ;
473- self . context . current_hour_relative_humidity = current_hour. relative_humidity . 0 . to_string ( ) ;
474- self . context . current_hour_relative_humidity_icon =
475- current_hour. relative_humidity . get_icon_path ( ) ;
476494 self . context . current_day_date = chrono:: Local :: now ( ) . format ( "%A, %d %B" ) . to_string ( ) ;
477495 self . context . current_hour_rain_amount =
478496 current_hour. rain . calculate_median_rain ( ) . to_string ( ) ;
479497 self . context . current_hour_rain_measure_icon = current_hour. rain . amount . get_icon_path ( ) ;
498+
480499 self
481500 }
482501
483- fn extract_curve_data ( svg_result : & [ GraphDataPath ] ) -> ( String , String , String ) {
484- svg_result. iter ( ) . fold (
485- ( String :: new ( ) , String :: new ( ) , String :: new ( ) ) ,
486- |( mut temp_acc, mut feel_like_acc, mut rain_acc) , path| {
487- match path {
488- GraphDataPath :: Temp ( data) => temp_acc. push_str ( data) ,
489- GraphDataPath :: TempFeelLike ( data) => feel_like_acc. push_str ( data) ,
490- GraphDataPath :: Rain ( data) => rain_acc. push_str ( data) ,
491- }
492- ( temp_acc, feel_like_acc, rain_acc)
493- } ,
494- )
502+ fn set_now_values_for_table ( & mut self , current_hour : & HourlyForecast ) {
503+ self . context . current_hour_wind_speed = current_hour. wind . get_speed ( ) . to_string ( ) ;
504+ self . context . current_hour_wind_icon = current_hour. wind . get_icon_path ( ) ;
505+ self . context . current_hour_uv_index = current_hour. uv . 0 . to_string ( ) ;
506+ self . context . current_hour_uv_index_icon = current_hour. uv . get_icon_path ( ) ;
507+ self . context . current_hour_relative_humidity = current_hour. relative_humidity . 0 . to_string ( ) ;
508+ self . context . current_hour_relative_humidity_icon =
509+ current_hour. relative_humidity . get_icon_path ( ) ;
495510 }
496511
497- fn set_max_values (
512+ fn set_max_values_for_table (
498513 & mut self ,
499514 hourly_forecast_data : & [ HourlyForecast ] ,
500- forecast_window_start : chrono:: DateTime < Utc > ,
501- day_end : chrono:: DateTime < Utc > ,
502- forecast_window_end : chrono:: DateTime < Utc > ,
515+ forecast_window_start : chrono:: DateTime < Local > ,
516+ day_end : chrono:: DateTime < Local > ,
517+ forecast_window_end : chrono:: DateTime < Local > ,
503518 ) {
504- let max_wind_today = find_max_item_between_dates (
505- hourly_forecast_data,
506- & forecast_window_start,
507- & day_end,
508- |item| item. wind . get_speed ( ) ,
509- |item| & item. time ,
519+ println ! ( "### Calculating table Max24h..." ) ;
520+ let today_duration = day_end
521+ . signed_duration_since ( forecast_window_start)
522+ . num_hours ( ) ;
523+ println ! (
524+ "Today's Forecast Window: start = {:?}, end = {:?}, duration = {} hours" ,
525+ forecast_window_start, day_end, today_duration
510526 ) ;
511527
512- let max_wind_tomorrow = find_max_item_between_dates (
513- hourly_forecast_data ,
514- & day_end ,
515- & forecast_window_end ,
516- |item| item . wind . get_speed ( ) ,
517- |item| & item . time ,
528+ let tomorrow_duration = forecast_window_end
529+ . signed_duration_since ( day_end )
530+ . num_hours ( ) ;
531+ println ! (
532+ "Tomorrow's Forecast Window: start = {:?}, end = {:?}, duration = {} hours" ,
533+ day_end , forecast_window_end , tomorrow_duration
518534 ) ;
519535
536+ macro_rules! max_in_today_and_tomorrow {
537+ ( $get_value: expr) => { {
538+ let get_time = |item: & HourlyForecast | item. time. with_timezone( & Local ) ;
539+ let max_today = find_max_item_between_dates(
540+ hourly_forecast_data,
541+ & forecast_window_start,
542+ & day_end,
543+ $get_value,
544+ get_time,
545+ ) ;
546+ let max_tomorrow = find_max_item_between_dates(
547+ hourly_forecast_data,
548+ & day_end,
549+ & forecast_window_end,
550+ $get_value,
551+ get_time,
552+ ) ;
553+ ( max_today, max_tomorrow)
554+ } } ;
555+ }
556+
557+ let ( max_wind_today, max_wind_tomorrow) =
558+ max_in_today_and_tomorrow ! ( |item| item. wind. get_speed( ) ) ;
559+
520560 if max_wind_today > max_wind_tomorrow {
521561 self . context . max_gust_speed = max_wind_today. to_string ( ) ;
522562 } else {
523563 self . context . max_gust_speed = max_wind_tomorrow. to_string ( ) ;
524564 self . context . max_gust_speed_font_style = FontStyle :: Italic . to_string ( ) ;
525565 }
526566
527- let max_uv_index = find_max_item_between_dates (
528- hourly_forecast_data,
529- & forecast_window_start,
530- & day_end,
531- |item| item. uv ,
532- |item| & item. time ,
533- ) ;
567+ let ( max_uv_index_today, max_uv_index_tomorrow) =
568+ max_in_today_and_tomorrow ! ( |item| item. uv) ;
534569
535- let max_uv_index_tomorrow = find_max_item_between_dates (
536- hourly_forecast_data,
537- & day_end,
538- & forecast_window_end,
539- |item| item. uv ,
540- |item| & item. time ,
541- ) ;
542-
543- if max_uv_index > max_uv_index_tomorrow {
544- self . context . max_uv_index = max_uv_index. 0 . to_string ( ) ;
570+ if max_uv_index_today > max_uv_index_tomorrow {
571+ self . context . max_uv_index = max_uv_index_today. 0 . to_string ( ) ;
545572 } else {
546573 self . context . max_uv_index = max_uv_index_tomorrow. 0 . to_string ( ) ;
547574 self . context . max_uv_index_font_style = FontStyle :: Italic . to_string ( ) ;
548575 }
549576
550- let max_relative_humidity = find_max_item_between_dates (
551- hourly_forecast_data,
552- & forecast_window_start,
553- & day_end,
554- |item| item. relative_humidity ,
555- |item| & item. time ,
556- ) ;
557-
558- let max_relative_humidity_tomorrow = find_max_item_between_dates (
559- hourly_forecast_data,
560- & day_end,
561- & forecast_window_end,
562- |item| item. relative_humidity ,
563- |item| & item. time ,
564- ) ;
577+ let ( max_relative_humidity_today, max_relative_humidity_tomorrow) =
578+ max_in_today_and_tomorrow ! ( |item| item. relative_humidity) ;
565579
566- if max_relative_humidity > max_relative_humidity_tomorrow {
567- self . context . max_relative_humidity = max_relative_humidity . 0 . to_string ( ) ;
580+ if max_relative_humidity_today > max_relative_humidity_tomorrow {
581+ self . context . max_relative_humidity = max_relative_humidity_today . 0 . to_string ( ) ;
568582 } else {
569583 self . context . max_relative_humidity = max_relative_humidity_tomorrow. 0 . to_string ( ) ;
570584 self . context . max_relative_humidity_font_style = FontStyle :: Italic . to_string ( ) ;
0 commit comments