/*! * Nyash Time Box - Time and Date operations * * 時間と日付操作を提供するBox型 * Everything is Box哲学に基づく時間ライブラリ */ use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox}; use std::fmt::{Debug, Display}; use std::any::Any; use std::time::{SystemTime, Duration}; use chrono::{DateTime, Local, TimeZone, Datelike, Timelike}; /// 時間操作を提供するBox #[derive(Debug, Clone)] pub struct TimeBox { id: u64, } impl TimeBox { pub fn new() -> Self { static mut COUNTER: u64 = 0; let id = unsafe { COUNTER += 1; COUNTER }; Self { id } } /// 現在時刻を取得 pub fn now(&self) -> Box { Box::new(DateTimeBox::now()) } /// UNIXタイムスタンプから日時を作成 pub fn fromTimestamp(&self, timestamp: Box) -> Box { if let Some(int_box) = timestamp.as_any().downcast_ref::() { Box::new(DateTimeBox::from_timestamp(int_box.value)) } else { Box::new(StringBox::new("Error: fromTimestamp() requires integer input")) } } /// 日時文字列をパース pub fn parse(&self, date_str: Box) -> Box { if let Some(string_box) = date_str.as_any().downcast_ref::() { match DateTimeBox::parse(&string_box.value) { Ok(dt) => Box::new(dt), Err(e) => Box::new(StringBox::new(&format!("Error: {}", e))), } } else { Box::new(StringBox::new("Error: parse() requires string input")) } } /// ミリ秒スリープ pub fn sleep(&self, millis: Box) -> Box { if let Some(int_box) = millis.as_any().downcast_ref::() { if int_box.value > 0 { std::thread::sleep(Duration::from_millis(int_box.value as u64)); Box::new(StringBox::new("ok")) } else { Box::new(StringBox::new("Error: sleep() requires positive milliseconds")) } } else { Box::new(StringBox::new("Error: sleep() requires integer input")) } } /// 現在時刻をフォーマット pub fn format(&self, format_str: Box) -> Box { if let Some(str_box) = format_str.as_any().downcast_ref::() { let now = Local::now(); let formatted = now.format(&str_box.value).to_string(); Box::new(StringBox::new(formatted)) } else { Box::new(StringBox::new("Error: format() requires string format pattern")) } } } impl NyashBox for TimeBox { fn type_name(&self) -> &'static str { "TimeBox" } fn to_string_box(&self) -> StringBox { StringBox::new("TimeBox()") } fn clone_box(&self) -> Box { Box::new(self.clone()) } fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_time) = other.as_any().downcast_ref::() { BoolBox::new(self.id == other_time.id) } else { BoolBox::new(false) } } fn as_any(&self) -> &dyn Any { self } fn box_id(&self) -> u64 { self.id } } impl Display for TimeBox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "TimeBox()") } } /// 日時を表すBox #[derive(Debug, Clone)] pub struct DateTimeBox { pub datetime: DateTime, id: u64, } impl DateTimeBox { /// 現在時刻で作成 pub fn now() -> Self { static mut COUNTER: u64 = 0; let id = unsafe { COUNTER += 1; COUNTER }; Self { datetime: Local::now(), id, } } /// UNIXタイムスタンプから作成 pub fn from_timestamp(timestamp: i64) -> Self { static mut COUNTER: u64 = 0; let id = unsafe { COUNTER += 1; COUNTER }; let datetime = Local.timestamp_opt(timestamp, 0).unwrap(); Self { datetime, id } } /// 文字列からパース pub fn parse(date_str: &str) -> Result { static mut COUNTER: u64 = 0; let id = unsafe { COUNTER += 1; COUNTER }; // ISO 8601形式でパース match DateTime::parse_from_rfc3339(date_str) { Ok(dt) => Ok(Self { datetime: dt.with_timezone(&Local), id, }), Err(_) => { // シンプルな形式でパース (YYYY-MM-DD HH:MM:SS) match chrono::NaiveDateTime::parse_from_str(date_str, "%Y-%m-%d %H:%M:%S") { Ok(naive_dt) => { let datetime = Local.from_local_datetime(&naive_dt).unwrap(); Ok(Self { datetime, id }) } Err(e) => Err(format!("Failed to parse date: {}", e)), } } } } /// 年を取得 pub fn year(&self) -> Box { Box::new(IntegerBox::new(self.datetime.year() as i64)) } /// 月を取得 pub fn month(&self) -> Box { Box::new(IntegerBox::new(self.datetime.month() as i64)) } /// 日を取得 pub fn day(&self) -> Box { Box::new(IntegerBox::new(self.datetime.day() as i64)) } /// 時を取得 pub fn hour(&self) -> Box { Box::new(IntegerBox::new(self.datetime.hour() as i64)) } /// 分を取得 pub fn minute(&self) -> Box { Box::new(IntegerBox::new(self.datetime.minute() as i64)) } /// 秒を取得 pub fn second(&self) -> Box { Box::new(IntegerBox::new(self.datetime.second() as i64)) } /// UNIXタイムスタンプを取得 pub fn timestamp(&self) -> Box { Box::new(IntegerBox::new(self.datetime.timestamp())) } /// ISO 8601形式でフォーマット pub fn toISOString(&self) -> Box { Box::new(StringBox::new(&self.datetime.to_rfc3339())) } /// カスタムフォーマット pub fn format(&self, fmt: Box) -> Box { if let Some(string_box) = fmt.as_any().downcast_ref::() { let formatted = self.datetime.format(&string_box.value).to_string(); Box::new(StringBox::new(&formatted)) } else { Box::new(StringBox::new("Error: format() requires string input")) } } /// 日付を加算 pub fn addDays(&self, days: Box) -> Box { if let Some(int_box) = days.as_any().downcast_ref::() { let new_datetime = self.datetime + chrono::Duration::days(int_box.value); Box::new(DateTimeBox { datetime: new_datetime, id: self.id, }) } else { Box::new(StringBox::new("Error: addDays() requires integer input")) } } /// 時間を加算 pub fn addHours(&self, hours: Box) -> Box { if let Some(int_box) = hours.as_any().downcast_ref::() { let new_datetime = self.datetime + chrono::Duration::hours(int_box.value); Box::new(DateTimeBox { datetime: new_datetime, id: self.id, }) } else { Box::new(StringBox::new("Error: addHours() requires integer input")) } } } impl NyashBox for DateTimeBox { fn type_name(&self) -> &'static str { "DateTimeBox" } fn to_string_box(&self) -> StringBox { StringBox::new(&self.datetime.format("%Y-%m-%d %H:%M:%S").to_string()) } fn clone_box(&self) -> Box { Box::new(self.clone()) } fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_dt) = other.as_any().downcast_ref::() { BoolBox::new(self.datetime == other_dt.datetime) } else { BoolBox::new(false) } } fn as_any(&self) -> &dyn Any { self } fn box_id(&self) -> u64 { self.id } } impl Display for DateTimeBox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.datetime.format("%Y-%m-%d %H:%M:%S")) } } /// タイマーを表すBox #[derive(Debug, Clone)] pub struct TimerBox { start_time: SystemTime, id: u64, } impl TimerBox { pub fn new() -> Self { static mut COUNTER: u64 = 0; let id = unsafe { COUNTER += 1; COUNTER }; Self { start_time: SystemTime::now(), id, } } /// 経過時間をミリ秒で取得 pub fn elapsed(&self) -> Box { match self.start_time.elapsed() { Ok(duration) => { let millis = duration.as_millis() as i64; Box::new(IntegerBox::new(millis)) } Err(_) => Box::new(IntegerBox::new(0)), } } /// タイマーをリセット pub fn reset(&mut self) -> Box { self.start_time = SystemTime::now(); Box::new(StringBox::new("Timer reset")) } } impl NyashBox for TimerBox { fn type_name(&self) -> &'static str { "TimerBox" } fn to_string_box(&self) -> StringBox { StringBox::new("TimerBox()") } fn clone_box(&self) -> Box { Box::new(self.clone()) } fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_timer) = other.as_any().downcast_ref::() { BoolBox::new(self.id == other_timer.id) } else { BoolBox::new(false) } } fn as_any(&self) -> &dyn Any { self } fn box_id(&self) -> u64 { self.id } } impl Display for TimerBox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "TimerBox()") } }