11use anyhow:: { Context , Result } ;
2- use chrono:: { DateTime , Local , NaiveDate } ;
2+ use chrono:: { DateTime , Local , NaiveDate , TimeZone } ;
33use std:: fs:: { self , File , OpenOptions } ;
44use std:: io:: { BufRead , BufReader , Read , Seek , SeekFrom , Write } ;
55use std:: path:: Path ;
66
7- use crate :: entry:: { Activity , Entry , MIDNIGHT_SEPARATOR_PREFIX } ;
7+ use crate :: entry:: { Activity , Entry , MIDNIGHT_SEPARATOR_PREFIX , HELLO_ENTRY_NAME } ;
88
99pub fn read_entries ( data_file : & Path ) -> Result < Vec < Entry > > {
1010 if !data_file. exists ( ) {
@@ -134,32 +134,58 @@ pub fn entries_to_activities(entries: &[Entry], start_date: Option<NaiveDate>, e
134134 let start_time = entries[ i] . datetime ;
135135 let end_time = entries[ i+1 ] . datetime ;
136136
137- // Apply date filtering if specified
138- // Only include activities that occur within the date range
139- if let Some ( start_date) = start_date {
140- if end_time. date_naive ( ) < start_date {
141- continue ; // Skip activities that end before the start date
142- }
143- }
137+ // Special handling for "hello" entries
138+ // Make the hello entry start at the beginning of the day instead of from the last entry of the previous day
139+ let adjusted_start_time = if entries[ i+1 ] . name == HELLO_ENTRY_NAME {
140+ // Use midnight of the current day as the start time for hello entries
141+ let naive_midnight = end_time. date_naive ( ) . and_time ( chrono:: NaiveTime :: from_hms_opt ( 0 , 0 , 0 ) . unwrap ( ) ) ;
142+ Local . from_local_datetime ( & naive_midnight) . single ( ) . unwrap ( )
143+ } else {
144+ start_time
145+ } ;
144146
145- if let Some ( end_date) = end_date {
146- if start_time. date_naive ( ) > end_date {
147- continue ; // Skip activities that start after the end date
148- }
149- }
147+ // Activities are defined by their end time (the timestamp when they were recorded)
148+ // The activity belongs to the day of its end timestamp
149+ let activity_date = end_time. date_naive ( ) ;
150150
151- // Only include activities where the end time is within the date range
152- // This ensures only activities that complete within the requested range are shown
151+ // Filter based on date range
153152 if let ( Some ( start_date) , Some ( end_date) ) = ( start_date, end_date) {
154- let activity_date = end_time . date_naive ( ) ;
153+ // Only include activities that end within the specified date range
155154 if activity_date < start_date || activity_date > end_date {
156155 continue ;
157156 }
157+
158+ // Additional check: if this is for a single day report (default "today" behavior)
159+ // and the start time is from a previous day, make sure it's only from the
160+ // immediately preceding day, unless it's a "hello" entry which we already adjusted
161+ if start_date == end_date && entries[ i+1 ] . name != HELLO_ENTRY_NAME {
162+ let start_activity_date = adjusted_start_time. date_naive ( ) ;
163+ if start_activity_date < activity_date {
164+ // Calculate days between the dates
165+ let days_between = ( activity_date - start_activity_date) . num_days ( ) ;
166+ if days_between > 1 {
167+ continue ; // Skip activities that started more than one day before
168+ }
169+ }
170+ }
171+ } else {
172+ // Apply date filtering if only one date boundary is specified
173+ if let Some ( start_date) = start_date {
174+ if activity_date < start_date {
175+ continue ; // Skip activities that end before the start date
176+ }
177+ }
178+
179+ if let Some ( end_date) = end_date {
180+ if activity_date > end_date {
181+ continue ; // Skip activities that end after the end date
182+ }
183+ }
158184 }
159185
160186 let activity = Activity :: new (
161187 entries[ i+1 ] . name . clone ( ) ,
162- start_time ,
188+ adjusted_start_time , // Use the adjusted start time
163189 end_time,
164190 false ,
165191 entries[ i+1 ] . comment . clone ( ) ,
@@ -181,15 +207,22 @@ pub fn filter_entries_by_date_range(entries: &[Entry], start_date: NaiveDate, en
181207
182208 // Find the last entry before the start date (needed for calculating the first activity's duration)
183209 // This handles the case where an activity starts before our date range but ends within it
210+ // Only include this entry if it's from the same day as start_date or from the immediate previous day
184211 let mut last_entry_before_range = None ;
185212 for entry in entries. iter ( ) . rev ( ) {
186- if entry. datetime . date_naive ( ) < start_date {
187- last_entry_before_range = Some ( entry. clone ( ) ) ;
213+ let entry_date = entry. datetime . date_naive ( ) ;
214+ if entry_date < start_date {
215+ // Only include the previous entry if it's from the same day or immediately before
216+ // This prevents showing activities from days far in the past
217+ let days_between = ( start_date - entry_date) . num_days ( ) ;
218+ if days_between <= 1 {
219+ last_entry_before_range = Some ( entry. clone ( ) ) ;
220+ }
188221 break ;
189222 }
190223 }
191224
192- // If we found a last entry before the range, include it
225+ // If we found a valid last entry before the range, include it
193226 if let Some ( entry) = last_entry_before_range {
194227 filtered_entries. push ( entry) ;
195228 }
0 commit comments