11use anyhow:: { Context , Result } ;
2- use chrono:: { DateTime , Local , NaiveDate , TimeZone } ;
2+ use chrono:: { DateTime , Local , NaiveDate } ;
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 , HELLO_ENTRY_NAME } ;
7+ use crate :: entry:: { Activity , Entry , HELLO_ENTRY_NAME , MIDNIGHT_SEPARATOR_PREFIX } ;
88
99pub fn read_entries ( data_file : & Path ) -> Result < Vec < Entry > > {
1010 if !data_file. exists ( ) {
@@ -118,7 +118,7 @@ pub fn entries_to_activities(entries: &[Entry], start_date: Option<NaiveDate>, e
118118 return activities;
119119 }
120120
121- // Create activities from consecutive entries, skipping midnight separators
121+ // Create activities from consecutive entries, skipping midnight separators and hello entries
122122 for i in 0 ..entries. len ( ) - 1 {
123123 // Skip if this is a midnight separator entry
124124 if entries[ i+1 ] . name . starts_with ( MIDNIGHT_SEPARATOR_PREFIX ) {
@@ -130,62 +130,46 @@ pub fn entries_to_activities(entries: &[Entry], start_date: Option<NaiveDate>, e
130130 continue ;
131131 }
132132
133+ // Skip if this is a hello entry - it marks the start of day only
134+ if entries[ i+1 ] . name == HELLO_ENTRY_NAME {
135+ continue ;
136+ }
137+
138+ // Skip if previous entry was a hello entry - hello doesn't create duration
139+ if entries[ i] . name == HELLO_ENTRY_NAME {
140+ continue ;
141+ }
142+
133143 // Get the start and end times
134144 let start_time = entries[ i] . datetime ;
135145 let end_time = entries[ i+1 ] . datetime ;
136146
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- } ;
147+ // Apply date filtering if specified
148+ // Only include activities that occur within the date range
149+ if let Some ( start_date) = start_date {
150+ if end_time. date_naive ( ) < start_date {
151+ continue ; // Skip activities that end before the start date
152+ }
153+ }
146154
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 ( ) ;
155+ if let Some ( end_date) = end_date {
156+ if start_time. date_naive ( ) > end_date {
157+ continue ; // Skip activities that start after the end date
158+ }
159+ }
150160
151- // Filter based on date range
161+ // Only include activities where the end time is within the date range
162+ // This ensures only activities that complete within the requested range are shown
152163 if let ( Some ( start_date) , Some ( end_date) ) = ( start_date, end_date) {
153- // Only include activities that end within the specified date range
164+ let activity_date = end_time . date_naive ( ) ;
154165 if activity_date < start_date || activity_date > end_date {
155166 continue ;
156167 }
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- }
184168 }
185169
186170 let activity = Activity :: new (
187171 entries[ i+1 ] . name . clone ( ) ,
188- adjusted_start_time , // Use the adjusted start time
172+ start_time ,
189173 end_time,
190174 false ,
191175 entries[ i+1 ] . comment . clone ( ) ,
@@ -207,22 +191,15 @@ pub fn filter_entries_by_date_range(entries: &[Entry], start_date: NaiveDate, en
207191
208192 // Find the last entry before the start date (needed for calculating the first activity's duration)
209193 // 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
211194 let mut last_entry_before_range = None ;
212195 for entry in entries. iter ( ) . rev ( ) {
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- }
196+ if entry. datetime . date_naive ( ) < start_date {
197+ last_entry_before_range = Some ( entry. clone ( ) ) ;
221198 break ;
222199 }
223200 }
224201
225- // If we found a valid last entry before the range, include it
202+ // If we found a last entry before the range, include it
226203 if let Some ( entry) = last_entry_before_range {
227204 filtered_entries. push ( entry) ;
228205 }
0 commit comments