using System.Globalization; using System.Text.RegularExpressions; using System.Windows; using AxCopilot.SDK; using AxCopilot.Themes; namespace AxCopilot.Handlers; /// /// 날짜/시간 변환기 핸들러. "date" 프리픽스로 사용합니다. /// 예: date → 현재 날짜/시간 + 유닉스 타임스탬프 /// date +30d → 오늘 + 30일 /// date -100d → 오늘 - 100일 /// date 2026-12-25 → 해당 날짜까지 D-day + 요일 /// date 1711584000 → 유닉스 타임스탬프 → 날짜 /// date to unix → 현재 시각의 유닉스 타임스탬프 /// Enter → 결과를 클립보드에 복사. /// public class DateCalcHandler : IActionHandler { public string? Prefix => "date"; public PluginMetadata Metadata => new( "DateCalc", "날짜 계산 · D-day · 타임스탬프 변환", "1.0", "AX"); private static readonly string[] DateFormats = ["yyyy-MM-dd", "yyyy/MM/dd", "yyyyMMdd", "MM/dd/yyyy", "dd-MM-yyyy"]; public Task> GetItemsAsync(string query, CancellationToken ct) { var q = query.Trim(); var now = DateTime.Now; var items = new List(); if (string.IsNullOrWhiteSpace(q)) { // 현재 날짜/시간 정보 var dayName = now.ToString("dddd", new CultureInfo("ko-KR")); items.Add(Item($"{now:yyyy-MM-dd} ({dayName})", $"{now:HH:mm:ss} · {now:yyyy-MM-dd}")); items.Add(Item($"유닉스 타임스탬프: {new DateTimeOffset(now).ToUnixTimeSeconds()}", "현재 시각의 Unix epoch")); items.Add(Item($"올해 {now.DayOfYear}일째 / 남은 일: {(new DateTime(now.Year, 12, 31) - now).Days}일", $"ISO 주차: {ISOWeek.GetWeekOfYear(now)}주")); return Task.FromResult>(items); } // +30d / -100d 패턴 var offsetMatch = Regex.Match(q, @"^([+-])(\d+)([dDwWmMyY])$"); if (offsetMatch.Success) { var sign = offsetMatch.Groups[1].Value == "+" ? 1 : -1; var val = int.Parse(offsetMatch.Groups[2].Value) * sign; var unit = offsetMatch.Groups[3].Value.ToLowerInvariant(); var target = unit switch { "d" => now.AddDays(val), "w" => now.AddDays(val * 7), "m" => now.AddMonths(val), "y" => now.AddYears(val), _ => now }; var dayName = target.ToString("dddd", new CultureInfo("ko-KR")); var diff = (target.Date - now.Date).Days; var diffStr = diff >= 0 ? $"오늘로부터 {diff}일 후" : $"오늘로부터 {Math.Abs(diff)}일 전"; items.Add(Item($"{target:yyyy-MM-dd} ({dayName})", diffStr)); return Task.FromResult>(items); } // 유닉스 타임스탬프 (10자리 또는 13자리 숫자) if (Regex.IsMatch(q, @"^\d{10,13}$") && long.TryParse(q, out long epoch)) { var ts = epoch > 9_999_999_999 ? epoch / 1000 : epoch; // 밀리초→초 var dt = DateTimeOffset.FromUnixTimeSeconds(ts).LocalDateTime; var dayName = dt.ToString("dddd", new CultureInfo("ko-KR")); items.Add(Item($"{dt:yyyy-MM-dd HH:mm:ss} ({dayName})", $"Unix {epoch} → 로컬 시간")); return Task.FromResult>(items); } // "to unix" / "unix" 키워드 if (q.Equals("unix", StringComparison.OrdinalIgnoreCase) || q.Equals("to unix", StringComparison.OrdinalIgnoreCase)) { var unix = new DateTimeOffset(now).ToUnixTimeSeconds(); items.Add(Item($"{unix}", $"현재 시각 ({now:yyyy-MM-dd HH:mm:ss}) → Unix 타임스탬프")); return Task.FromResult>(items); } // 날짜 파싱 → D-day 계산 if (DateTime.TryParseExact(q, DateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsed)) { var dayName = parsed.ToString("dddd", new CultureInfo("ko-KR")); var diff = (parsed.Date - now.Date).Days; var dday = diff switch { 0 => "오늘", > 0 => $"D-{diff} (앞으로 {diff}일)", _ => $"D+{Math.Abs(diff)} ({Math.Abs(diff)}일 지남)" }; items.Add(Item($"{parsed:yyyy-MM-dd} ({dayName})", dday)); return Task.FromResult>(items); } items.Add(new LauncherItem( "날짜 형식을 인식할 수 없습니다", "예: +30d, -100d, 2026-12-25, 1711584000, unix", null, null, Symbol: Symbols.Warning)); return Task.FromResult>(items); } private static LauncherItem Item(string title, string subtitle) => new(title, $"{subtitle} · Enter로 복사", null, title, Symbol: Symbols.Clock); public Task ExecuteAsync(LauncherItem item, CancellationToken ct) { if (item.Data is string text && !string.IsNullOrWhiteSpace(text)) { try { Application.Current?.Dispatcher.Invoke(() => Clipboard.SetText(text)); } catch { } } return Task.CompletedTask; } }