1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use crate::{
commands::{Cli, Config, Result, current_job, from_end, from_start},
jobber::JobberWork,
print_tip,
};
use clap::Parser;
use color_print::cprintln;
/// Add a working position
///
/// Like start and end together in one command.
///
/// This function can be undone with `jobber undo`.
#[derive(Parser, Debug)]
pub(crate) struct Add {
/// Date/time work begins
///
/// Available formats:
///
/// | Example | Description |
/// | ---------------------|------------------------|
/// | `now` | current time |
/// | `"2026-05-31 13:15"` | date/time |
/// | `13:15` | time today |
/// | `15m` | minutes in past |
/// | `+15m` | minutes in future |
/// | `8h` | hours in past |
/// | `+8h` | hours in future |
#[clap(verbatim_doc_comment)]
start: String,
/// Time when work ended (or current time if not given)
///
/// Available formats:
///
/// | Example | Description |
/// | ---------------------|-----------------------|
/// | `now` | current time |
/// | `"2026-05-31 13:15"` | date/time |
/// | `13:15` | time behind start |
/// | `15m` | minutes past start |
/// | `8h` | hours past start |
#[clap(verbatim_doc_comment)]
end: String,
/// Subject of the work
subject: String,
/// Comma-separated list of tags (no spaces allowed e.g. support,test)
#[clap(short, long, value_delimiter = ',')]
tags: Vec<String>,
/// ID of the job to add work for (default is current job)
#[clap(short, long)]
job: Option<usize>,
}
impl Add {
pub(crate) fn run(&self, cli: &Cli) -> Result<()> {
let config = Config::load()?;
let mut database = cli.open_database()?;
let start = from_start(&self.start)?;
let end = from_end(&self.end, start)?;
let job_id = self.job.unwrap_or(current_job(&config, &database)?);
database.add_work(job_id, start, end, self.subject.clone(), self.tags.clone())?;
cli.close_database(database)?;
cprintln!("Successfully added new work to job <s>{job_id}</>.");
if !cli.no_tips {
print_tip!(cli);
print_tip!(
cli,
"Use <s>jobber show work{}</> to take a view.",
self.job.map(|j| format!(" {j}")).unwrap_or_default()
);
}
Ok(())
}
}