129 lines
5.3 KiB
C#
129 lines
5.3 KiB
C#
using System.Globalization;
|
|
using System.Text.RegularExpressions;
|
|
using System.Windows;
|
|
using AxCopilot.SDK;
|
|
using AxCopilot.Themes;
|
|
|
|
namespace AxCopilot.Handlers;
|
|
|
|
/// <summary>
|
|
/// 날짜/시간 변환기 핸들러. "date" 프리픽스로 사용합니다.
|
|
/// 예: date → 현재 날짜/시간 + 유닉스 타임스탬프
|
|
/// date +30d → 오늘 + 30일
|
|
/// date -100d → 오늘 - 100일
|
|
/// date 2026-12-25 → 해당 날짜까지 D-day + 요일
|
|
/// date 1711584000 → 유닉스 타임스탬프 → 날짜
|
|
/// date to unix → 현재 시각의 유닉스 타임스탬프
|
|
/// Enter → 결과를 클립보드에 복사.
|
|
/// </summary>
|
|
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<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
|
|
{
|
|
var q = query.Trim();
|
|
var now = DateTime.Now;
|
|
var items = new List<LauncherItem>();
|
|
|
|
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<IEnumerable<LauncherItem>>(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<IEnumerable<LauncherItem>>(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<IEnumerable<LauncherItem>>(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<IEnumerable<LauncherItem>>(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<IEnumerable<LauncherItem>>(items);
|
|
}
|
|
|
|
items.Add(new LauncherItem(
|
|
"날짜 형식을 인식할 수 없습니다",
|
|
"예: +30d, -100d, 2026-12-25, 1711584000, unix",
|
|
null, null, Symbol: Symbols.Warning));
|
|
|
|
return Task.FromResult<IEnumerable<LauncherItem>>(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;
|
|
}
|
|
}
|