Skip to content

Commit 0049097

Browse files
author
Per-Gunnar Eriksson
committed
Reset daily functionality added
1 parent d69b6e9 commit 0049097

File tree

4 files changed

+145
-25
lines changed

4 files changed

+145
-25
lines changed

src/commands/hello.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use anyhow::Result;
2+
use chrono::{Local, NaiveTime, TimeZone};
23

34
use crate::config::Config;
4-
use crate::entry::{Entry, HELLO_ENTRY_NAME};
5+
use crate::entry::{Entry, HELLO_ENTRY_NAME, MIDNIGHT_SEPARATOR_PREFIX};
56
use crate::storage;
67
use crate::util;
78

@@ -10,15 +11,48 @@ pub fn execute(cli: &crate::Cli, config: &Config) -> Result<()> {
1011
// Determine current time, either from command line or system
1112
let now = util::parse_now_arg(cli.now.as_deref())?;
1213

13-
// Create a hello entry
14-
let entry = Entry::new(now, HELLO_ENTRY_NAME.to_string(), false, None);
15-
1614
// Get data file path
1715
let data_file = cli.data.as_ref().map(std::path::PathBuf::from).unwrap_or_else(|| config.data_file.clone());
1816

1917
// Create directory structure if needed
2018
crate::config::ensure_data_dir(&data_file)?;
2119

20+
// Check if there are existing entries
21+
let existing_entries = storage::read_entries(&data_file)?;
22+
23+
// Check if we need to create a midnight separator
24+
let create_midnight_separator = if !existing_entries.is_empty() {
25+
let last_entry = existing_entries.last().unwrap();
26+
let last_entry_date = last_entry.datetime.date_naive();
27+
let current_date = now.date_naive();
28+
29+
// If the last entry is from a previous day, we should add a midnight separator
30+
last_entry_date < current_date
31+
} else {
32+
false
33+
};
34+
35+
// If needed, add a midnight separator entry
36+
if create_midnight_separator {
37+
// Create a midnight entry at 00:00 of the current day
38+
let midnight_naive = now.date_naive().and_time(NaiveTime::from_hms_opt(0, 0, 0).unwrap());
39+
let midnight = Local.from_local_datetime(&midnight_naive).single().unwrap();
40+
41+
// Create a midnight separator entry
42+
let midnight_entry = Entry::new(
43+
midnight,
44+
format!("{}", MIDNIGHT_SEPARATOR_PREFIX),
45+
false,
46+
None
47+
);
48+
49+
// Write the midnight separator to the log file
50+
storage::append_entry(&data_file, &midnight_entry)?;
51+
}
52+
53+
// Create a hello entry
54+
let entry = Entry::new(now, HELLO_ENTRY_NAME.to_string(), false, None);
55+
2256
// Write the entry to the log file
2357
storage::append_entry(&data_file, &entry)?;
2458

src/commands/report.rs

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,39 @@ pub fn execute(
3232
// Get data file path
3333
let data_file = cli.data.as_ref().map(std::path::PathBuf::from).unwrap_or_else(|| config.data_file.clone());
3434

35-
// Read entries from the log file
36-
let entries = storage::read_entries(&data_file)?;
35+
// Read all entries from the log file
36+
let all_entries = storage::read_entries(&data_file)?;
37+
38+
// Filter entries by date range considering midnight separators
39+
let filtered_entries = storage::filter_entries_by_date_range(
40+
&all_entries,
41+
range.start_date,
42+
range.end_date
43+
);
3744

3845
// Convert entries to activities
39-
let mut activities = storage::entries_to_activities(&entries);
46+
let mut activities = storage::entries_to_activities(&filtered_entries);
4047

4148
// Add current activity if requested
42-
if !no_current_activity && !entries.is_empty() {
43-
let current_activity_name = if current_activity.is_empty() {
44-
"-- Current Activity --"
45-
} else {
46-
current_activity
47-
};
48-
49-
let current = storage::create_current_activity(
50-
entries.last().unwrap(),
51-
now,
52-
current_activity_name
53-
);
49+
if !no_current_activity && !filtered_entries.is_empty() {
50+
let last_entry = filtered_entries.last().unwrap();
5451

55-
activities.push(current);
52+
// Only add current activity if the last entry is from today
53+
if last_entry.datetime.date_naive() == now.date_naive() {
54+
let current_activity_name = if current_activity.is_empty() {
55+
"-- Current Activity --"
56+
} else {
57+
current_activity
58+
};
59+
60+
let current = storage::create_current_activity(
61+
last_entry,
62+
now,
63+
current_activity_name
64+
);
65+
66+
activities.push(current);
67+
}
5668
}
5769

5870
// Create report options

src/entry.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ use serde::{Deserialize, Serialize};
55
use std::fmt;
66
use std::hash::{Hash, Hasher};
77

8-
// Constants for activity types
8+
// Constants for entry types
99
pub const HELLO_ENTRY_NAME: &str = "hello";
10+
pub const MIDNIGHT_SEPARATOR_PREFIX: &str = "--- Midnight: New Day ---";
1011

1112
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1213
pub enum ActivityType {
@@ -135,7 +136,10 @@ impl Activity {
135136
let duration = end.signed_duration_since(start);
136137
let project = Entry::new(start, name.clone(), false, None).project();
137138
let task = Entry::new(start, name.clone(), false, None).task();
138-
let activity_type = if name.ends_with("***") {
139+
140+
let activity_type = if name.starts_with(MIDNIGHT_SEPARATOR_PREFIX) {
141+
ActivityType::Ignored
142+
} else if name.ends_with("***") {
139143
ActivityType::Ignored
140144
} else if name.ends_with("**") {
141145
ActivityType::Break

src/storage.rs

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use anyhow::{Context, Result};
2-
use chrono::{DateTime, Local};
2+
use chrono::{DateTime, Local, NaiveDate};
33
use std::fs::{self, File, OpenOptions};
44
use std::io::{BufRead, BufReader, Read, Seek, SeekFrom, Write};
55
use std::path::Path;
66

7-
use crate::entry::{Activity, Entry};
7+
use crate::entry::{Activity, Entry, HELLO_ENTRY_NAME, MIDNIGHT_SEPARATOR_PREFIX};
88

99
pub fn read_entries(data_file: &Path) -> Result<Vec<Entry>> {
1010
if !data_file.exists() {
@@ -118,8 +118,18 @@ pub fn entries_to_activities(entries: &[Entry]) -> Vec<Activity> {
118118
return activities;
119119
}
120120

121-
// Create activities from consecutive entries
121+
// Create activities from consecutive entries, skipping midnight separators
122122
for i in 0..entries.len() - 1 {
123+
// Skip if this is a midnight separator entry
124+
if entries[i+1].name.starts_with(MIDNIGHT_SEPARATOR_PREFIX) {
125+
continue;
126+
}
127+
128+
// Skip if previous entry was a midnight separator
129+
if entries[i].name.starts_with(MIDNIGHT_SEPARATOR_PREFIX) {
130+
continue;
131+
}
132+
123133
let activity = Activity::new(
124134
entries[i+1].name.clone(),
125135
entries[i].datetime,
@@ -134,6 +144,66 @@ pub fn entries_to_activities(entries: &[Entry]) -> Vec<Activity> {
134144
activities
135145
}
136146

147+
pub fn filter_entries_by_date_range(entries: &[Entry], start_date: NaiveDate, end_date: NaiveDate) -> Vec<Entry> {
148+
let mut filtered_entries = Vec::new();
149+
let mut current_day_entries = Vec::new();
150+
let mut current_date = None;
151+
152+
for entry in entries {
153+
let entry_date = entry.datetime.date_naive();
154+
155+
// Check if this is a midnight separator
156+
if entry.name.starts_with(MIDNIGHT_SEPARATOR_PREFIX) {
157+
// Save current day entries if they are in range
158+
if let Some(date) = current_date {
159+
if date >= start_date && date <= end_date {
160+
filtered_entries.extend(current_day_entries.drain(..));
161+
} else {
162+
current_day_entries.clear();
163+
}
164+
}
165+
166+
// Start a new day
167+
current_date = Some(entry_date);
168+
current_day_entries.push(entry.clone());
169+
continue;
170+
}
171+
172+
// If we've encountered a hello entry without a preceding midnight separator
173+
if entry.name == HELLO_ENTRY_NAME && (current_date.is_none() || current_date.unwrap() != entry_date) {
174+
// Save current day entries if they are in range
175+
if let Some(date) = current_date {
176+
if date >= start_date && date <= end_date {
177+
filtered_entries.extend(current_day_entries.drain(..));
178+
} else {
179+
current_day_entries.clear();
180+
}
181+
}
182+
183+
// Start a new day
184+
current_date = Some(entry_date);
185+
current_day_entries.push(entry.clone());
186+
continue;
187+
}
188+
189+
// Regular entry, add to current day
190+
if current_date.is_none() {
191+
current_date = Some(entry_date);
192+
}
193+
194+
current_day_entries.push(entry.clone());
195+
}
196+
197+
// Don't forget to process the last day
198+
if let Some(date) = current_date {
199+
if date >= start_date && date <= end_date {
200+
filtered_entries.extend(current_day_entries);
201+
}
202+
}
203+
204+
filtered_entries
205+
}
206+
137207
pub fn create_current_activity(
138208
last_entry: &Entry,
139209
now: DateTime<Local>,

0 commit comments

Comments
 (0)