(block: &SessionBlock, compact: bool)
| 208 | } |
| 209 | |
| 210 | fn format_block_time(block: &SessionBlock, compact: bool) -> String { |
| 211 | let start = format_local_block_start(block.start_time, compact); |
| 212 | if block.is_gap { |
| 213 | let end = format_local_block_end(block.end_time, compact); |
| 214 | let duration = block.end_time.duration_since(block.start_time) / MILLIS_PER_HOUR; |
| 215 | return if compact { |
| 216 | format!("{start}-{end}\n({duration}h gap)") |
| 217 | } else { |
| 218 | format!("{start} - {end} ({duration}h gap)") |
| 219 | }; |
| 220 | } |
| 221 | |
| 222 | if block.is_active { |
| 223 | let now = utc_now(); |
| 224 | let elapsed = now.duration_since(block.start_time) / MILLIS_PER_MINUTE; |
| 225 | let remaining = block.end_time.duration_since(now) / MILLIS_PER_MINUTE; |
| 226 | let elapsed_hours = elapsed / 60; |
| 227 | let elapsed_minutes = elapsed.rem_euclid(60); |
| 228 | let remaining_hours = remaining / 60; |
| 229 | let remaining_minutes = remaining.rem_euclid(60); |
| 230 | return if compact { |
| 231 | format!( |
| 232 | "{start}\n({elapsed_hours}h{elapsed_minutes}m/{remaining_hours}h{remaining_minutes}m)" |
| 233 | ) |
| 234 | } else { |
| 235 | format!( |
| 236 | "{start} ({elapsed_hours}h {elapsed_minutes}m elapsed, {remaining_hours}h {remaining_minutes}m remaining)" |
| 237 | ) |
| 238 | }; |
| 239 | } |
| 240 | |
| 241 | let duration = block |
| 242 | .actual_end_time |
| 243 | .map(|end| end.duration_since(block.start_time) / MILLIS_PER_MINUTE) |
| 244 | .unwrap_or(0); |
| 245 | let hours = duration / 60; |
| 246 | let minutes = duration.rem_euclid(60); |
| 247 | if compact { |
| 248 | if hours > 0 { |
| 249 | format!("{start}\n({hours}h{minutes}m)") |
| 250 | } else { |
| 251 | format!("{start}\n({minutes}m)") |
| 252 | } |
| 253 | } else if hours > 0 { |
| 254 | format!("{start} ({hours}h {minutes}m)") |
| 255 | } else { |
| 256 | format!("{start} ({minutes}m)") |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | fn format_local_block_start(timestamp: TimestampMs, compact: bool) -> String { |
| 261 | let parts = local_parts(timestamp); |
nothing calls this directly
no test coverage detected