dtime 1.0.2

A professional, cross-platform datetime display utility with colored output and millisecond precision
Documentation
// File: src\display.rs
// Author: Hadi Cahyadi <cumulus13@gmail.com>
// Date: 2026-05-09
// Description:
// License: MIT

use crate::DateTimeInfo;
use colored::Colorize;

/// Color theme configuration
pub struct ColorTheme {
    pub title: (u8, u8, u8),
    pub local_time: (u8, u8, u8),
    pub utc_time: (u8, u8, u8),
    pub unix_sec: (u8, u8, u8),
    pub unix_ms: (u8, u8, u8),
    pub tz_title: (u8, u8, u8),
    pub tz_name: (u8, u8, u8),
    pub tz_offset: (u8, u8, u8),
    pub weekday: (u8, u8, u8),
    pub iso_label: (u8, u8, u8),
    pub iso_value: (u8, u8, u8),
}

impl Default for ColorTheme {
    fn default() -> Self {
        Self {
            title: (0xFF, 0x6B, 0x35),      // Orange
            local_time: (0x00, 0xD2, 0xFF), // Cyan Blue
            utc_time: (0x7B, 0x2F, 0xBE),   // Purple
            unix_sec: (0x00, 0xFF, 0x87),   // Neon Green
            unix_ms: (0xFF, 0xD7, 0x00),    // Neon Green
            tz_title: (0xFF, 0xD7, 0x00),   // Gold
            tz_name: (0x1E, 0x90, 0xFF),    // Dodger Blue
            tz_offset: (0xFF, 0x8C, 0x00),  // Dark Orange
            weekday: (0x00, 0xE5, 0xFF),    // Bright Cyan
            iso_label: (0xDA, 0x70, 0xD6),  // Orchid
            iso_value: (0xFF, 0xD7, 0x00),  // Gold
        }
    }
}

/// Format datetime info with colors
pub fn format_colored(dt: &DateTimeInfo) -> String {
    let theme = ColorTheme::default();
    let mut output = String::new();

    // Title
    output.push_str(&format!(
        "{}\n",
        "╔════════════════════════════════════════════════╗"
            .truecolor(theme.title.0, theme.title.1, theme.title.2)
            .bold()
    ));
    output.push_str(&format!(
        "{}\n",
        "║          SYSTEM TIME INFORMATION               ║"
            .truecolor(theme.title.0, theme.title.1, theme.title.2)
            .bold()
    ));
    output.push_str(&format!(
        "{}\n",
        "╚════════════════════════════════════════════════╝"
            .truecolor(theme.title.0, theme.title.1, theme.title.2)
            .bold()
    ));

    // Separator
    output.push_str(&format!(
        "{}\n",
        "┌────────────────────────────────────────────────┐".truecolor(150, 150, 150)
    ));

    // Local Time
    output.push_str(&format!(
        "│ {:<15} {:<30} │\n",
        "Local Time:"
            .truecolor(theme.local_time.0, theme.local_time.1, theme.local_time.2)
            .bold(),
        dt.local_time
            .truecolor(theme.local_time.0, theme.local_time.1, theme.local_time.2)
    ));

    // UTC Time
    output.push_str(&format!(
        "│ {:<15} {:<30} │\n",
        "UTC Time:"
            .truecolor(theme.utc_time.0, theme.utc_time.1, theme.utc_time.2)
            .bold(),
        dt.utc_time
            .truecolor(theme.utc_time.0, theme.utc_time.1, theme.utc_time.2)
    ));

    // Unix Seconds
    output.push_str(&format!(
        "│ {:<15} {:<30} │\n",
        "Unix Sec:"
            .truecolor(theme.unix_sec.0, theme.unix_sec.1, theme.unix_sec.2)
            .bold(),
        dt.unix_seconds
            .to_string()
            .truecolor(theme.unix_sec.0, theme.unix_sec.1, theme.unix_sec.2)
    ));

    // Unix Milliseconds
    output.push_str(&format!(
        "│ {:<15} {:<30} │\n",
        "Unix MS:"
            .truecolor(theme.unix_ms.0, theme.unix_ms.1, theme.unix_ms.2)
            .bold(),
        dt.unix_milliseconds.to_string().truecolor(
            theme.unix_ms.0,
            theme.unix_ms.1,
            theme.unix_ms.2
        )
    ));

    output.push_str(&format!(
        "{}\n",
        "└────────────────────────────────────────────────┘".truecolor(150, 150, 150)
    ));

    output.push('\n');

    // Timezone Information
    output.push_str(&format!(
        "{}\n",
        "╔════════════════════════════════════════════════╗"
            .truecolor(theme.tz_title.0, theme.tz_title.1, theme.tz_title.2)
            .bold()
    ));
    output.push_str(&format!(
        "{}\n",
        "║          TIMEZONE INFORMATION                  ║"
            .truecolor(theme.tz_title.0, theme.tz_title.1, theme.tz_title.2)
            .bold()
    ));
    output.push_str(&format!(
        "{}\n",
        "╚════════════════════════════════════════════════╝"
            .truecolor(theme.tz_title.0, theme.tz_title.1, theme.tz_title.2)
            .bold()
    ));

    output.push_str(&format!(
        "{}\n",
        "┌────────────────────────────────────────────────┐".truecolor(150, 150, 150)
    ));

    // Timezone name
    output.push_str(&format!(
        "│ {:<15} {:<30} │\n",
        "Timezone:"
            .truecolor(theme.tz_name.0, theme.tz_name.1, theme.tz_name.2)
            .bold(),
        dt.timezone
            .truecolor(theme.tz_name.0, theme.tz_name.1, theme.tz_name.2)
    ));

    // Offset
    output.push_str(&format!(
        "│ {:<15} {:<30} │\n",
        "Offset:"
            .truecolor(theme.tz_offset.0, theme.tz_offset.1, theme.tz_offset.2)
            .bold(),
        dt.offset
            .truecolor(theme.tz_offset.0, theme.tz_offset.1, theme.tz_offset.2)
    ));

    // Weekday
    output.push_str(&format!(
        "│ {:<15} {:<30} │\n",
        "Weekday:"
            .truecolor(theme.weekday.0, theme.weekday.1, theme.weekday.2)
            .bold(),
        dt.weekday
            .truecolor(theme.weekday.0, theme.weekday.1, theme.weekday.2)
    ));

    output.push_str(&format!(
        "{}\n",
        "└────────────────────────────────────────────────┘".truecolor(150, 150, 150)
    ));

    // ISO format if enabled
    if dt.config.show_iso {
        output.push('\n');
        output.push_str(&format!(
            "{}\n",
            "╔══════════════════════════════════════════════════╗"
                .truecolor(theme.iso_label.0, theme.iso_label.1, theme.iso_label.2)
                .bold()
        ));
        output.push_str(&format!(
            "{}\n",
            "║         ISO 8601 FORMAT                          ║"
                .truecolor(theme.iso_label.0, theme.iso_label.1, theme.iso_label.2)
                .bold()
        ));
        output.push_str(&format!(
            "{}\n",
            "╚══════════════════════════════════════════════════╝"
                .truecolor(theme.iso_label.0, theme.iso_label.1, theme.iso_label.2)
                .bold()
        ));
        output.push_str(&format!(
            "{}\n",
            "┌───────────────────────────────────────────────┐".truecolor(150, 150, 150)
        ));
        output.push_str(&format!(
            "│ {:<15} {:<30} │\n",
            "Local:"
                .truecolor(theme.iso_value.0, theme.iso_value.1, theme.iso_value.2)
                .bold(),
            dt.iso_local
                .truecolor(theme.iso_value.0, theme.iso_value.1, theme.iso_value.2)
        ));
        output.push_str(&format!(
            "│ {:<15} {:<30} │\n",
            "UTC:"
                .truecolor(theme.iso_value.0, theme.iso_value.1, theme.iso_value.2)
                .bold(),
            dt.iso_utc
                .truecolor(theme.iso_value.0, theme.iso_value.1, theme.iso_value.2)
        ));
        output.push_str(&format!(
            "{}\n",
            "└────────────────────────────────────────────┘".truecolor(150, 150, 150)
        ));
    }

    output
}

/// Format datetime info without colors
pub fn format_plain(dt: &DateTimeInfo) -> String {
    let mut output = String::new();

    output.push_str("=== System Time Information ===\n");
    output.push_str(&format!("Local Time : {}\n", dt.local_time));
    output.push_str(&format!("UTC Time   : {}\n", dt.utc_time));
    output.push_str(&format!("Unix Sec   : {}\n", dt.unix_seconds));
    output.push_str(&format!("Unix MS    : {}\n", dt.unix_milliseconds));
    output.push('\n');
    output.push_str("=== Timezone Information ===\n");
    output.push_str(&format!("Timezone   : {}\n", dt.timezone));
    output.push_str(&format!("Offset     : {}\n", dt.offset));
    output.push_str(&format!("Weekday    : {}\n", dt.weekday));

    if dt.config.show_iso {
        output.push('\n');
        output.push_str("=== ISO 8601 Format ===\n");
        output.push_str(&format!("Local ISO  : {}\n", dt.iso_local));
        output.push_str(&format!("UTC ISO    : {}\n", dt.iso_utc));
    }

    output
}