1pub mod approx;
4pub mod parse;
5pub mod show;
6pub mod tm;
7
8use show::{parse_date_format, DateMode, DateModeType};
9use std::mem::size_of;
10use tm::{atoi_bytes, parse_timestamp_prefix, Timestamp};
11
12pub enum TestToolDateResult {
14 Output(Vec<String>),
15 Exit(i32),
16}
17
18pub fn test_tool_date(args: &[String]) -> Result<TestToolDateResult, String> {
20 if std::env::var_os("GIT_TEST_DATE_NOW").is_some() && std::env::var_os("TZ").is_none() {
23 std::env::set_var("TZ", "UTC");
24 unsafe extern "C" {
26 fn tzset();
27 }
28 unsafe {
29 tzset();
30 }
31 }
32 if args.is_empty() {
33 return Err("test-tool date: missing subcommand".to_string());
34 }
35 let sub = args[0].as_str();
36 let rest = &args[1..];
37
38 match sub {
39 "is64bit" => {
40 let code = if size_of::<Timestamp>() == 8 { 0 } else { 1 };
42 Ok(TestToolDateResult::Exit(code))
43 }
44 "time_t-is64bit" => {
45 let code = if size_of::<libc::time_t>() == 8 { 0 } else { 1 };
46 Ok(TestToolDateResult::Exit(code))
47 }
48 "relative" => {
49 let mut lines = Vec::new();
50 for a in rest {
51 let t: u64 = a
52 .parse()
53 .map_err(|_| format!("test-tool date relative: bad integer {a}"))?;
54 let s = show::show_date_relative(t, tm::get_time_sec());
55 lines.push(format!("{a} -> {s}"));
56 }
57 Ok(TestToolDateResult::Output(lines))
58 }
59 "human" => {
60 let mut lines = Vec::new();
61 for a in rest {
62 let t: u64 = a
63 .parse()
64 .map_err(|_| format!("test-tool date human: bad integer {a}"))?;
65 let mut mode = DateMode::from_type(DateModeType::Human);
66 let s = show::show_date(t, 0, &mut mode);
67 show::date_mode_release(&mut mode);
68 lines.push(format!("{a} -> {s}"));
69 }
70 Ok(TestToolDateResult::Output(lines))
71 }
72 "parse" => {
73 let mut lines = Vec::new();
74 for a in rest {
75 match parse::parse_date(a) {
76 Ok(ds) => {
77 let parts: Vec<&str> = ds.split_whitespace().collect();
78 if parts.len() >= 2 {
79 let t: u64 = parts[0].parse().map_err(|_| "bad parse output")?;
80 let tz = atoi_bytes(parts[1].as_bytes());
81 let mut mode = DateMode::from_type(DateModeType::Iso8601);
82 let out = show::show_date(t, tz, &mut mode);
83 show::date_mode_release(&mut mode);
84 lines.push(format!("{a} -> {out}"));
85 } else {
86 lines.push(format!("{a} -> bad"));
87 }
88 }
89 Err(()) => lines.push(format!("{a} -> bad")),
90 }
91 }
92 Ok(TestToolDateResult::Output(lines))
93 }
94 "approxidate" => {
95 let mut lines = Vec::new();
96 for a in rest {
97 let mut err = 0;
98 let t = approx::approxidate_careful(a, Some(&mut err));
99 let mut mode = DateMode::from_type(DateModeType::Iso8601);
100 let out = show::show_date(t, 0, &mut mode);
101 show::date_mode_release(&mut mode);
102 lines.push(format!("{a} -> {out}"));
103 }
104 Ok(TestToolDateResult::Output(lines))
105 }
106 s if s.starts_with("show:") => {
107 let format = s.strip_prefix("show:").unwrap_or("");
108 let mut mode = parse_date_format(format).map_err(|e| e.to_string())?;
109 let mut lines = Vec::new();
110 for a in rest {
111 let b = a.as_bytes();
112 let (t, n) = parse_timestamp_prefix(b);
113 let mut rest_b = &b[n..];
114 while rest_b.first() == Some(&b' ') {
115 rest_b = &rest_b[1..];
116 }
117 let tz = atoi_bytes(rest_b);
118 let s = show::show_date(t, tz, &mut mode);
119 lines.push(format!("{a} -> {s}"));
120 }
121 show::date_mode_release(&mut mode);
122 Ok(TestToolDateResult::Output(lines))
123 }
124 _ => Err(format!("test-tool date: unknown subcommand '{sub}'")),
125 }
126}