Files
hakorune/src/boxes/time_box.rs

366 lines
10 KiB
Rust
Raw Normal View History

/*!
* 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<dyn NyashBox> {
Box::new(DateTimeBox::now())
}
/// UNIXタイムスタンプから日時を作成
pub fn fromTimestamp(&self, timestamp: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(int_box) = timestamp.as_any().downcast_ref::<IntegerBox>() {
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<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(string_box) = date_str.as_any().downcast_ref::<StringBox>() {
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<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(int_box) = millis.as_any().downcast_ref::<IntegerBox>() {
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<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(str_box) = format_str.as_any().downcast_ref::<StringBox>() {
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<dyn NyashBox> {
Box::new(self.clone())
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_time) = other.as_any().downcast_ref::<TimeBox>() {
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<Local>,
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<Self, String> {
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<dyn NyashBox> {
Box::new(IntegerBox::new(self.datetime.year() as i64))
}
/// 月を取得
pub fn month(&self) -> Box<dyn NyashBox> {
Box::new(IntegerBox::new(self.datetime.month() as i64))
}
/// 日を取得
pub fn day(&self) -> Box<dyn NyashBox> {
Box::new(IntegerBox::new(self.datetime.day() as i64))
}
/// 時を取得
pub fn hour(&self) -> Box<dyn NyashBox> {
Box::new(IntegerBox::new(self.datetime.hour() as i64))
}
/// 分を取得
pub fn minute(&self) -> Box<dyn NyashBox> {
Box::new(IntegerBox::new(self.datetime.minute() as i64))
}
/// 秒を取得
pub fn second(&self) -> Box<dyn NyashBox> {
Box::new(IntegerBox::new(self.datetime.second() as i64))
}
/// UNIXタイムスタンプを取得
pub fn timestamp(&self) -> Box<dyn NyashBox> {
Box::new(IntegerBox::new(self.datetime.timestamp()))
}
/// ISO 8601形式でフォーマット
pub fn toISOString(&self) -> Box<dyn NyashBox> {
Box::new(StringBox::new(&self.datetime.to_rfc3339()))
}
/// カスタムフォーマット
pub fn format(&self, fmt: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(string_box) = fmt.as_any().downcast_ref::<StringBox>() {
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<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(int_box) = days.as_any().downcast_ref::<IntegerBox>() {
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<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(int_box) = hours.as_any().downcast_ref::<IntegerBox>() {
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<dyn NyashBox> {
Box::new(self.clone())
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_dt) = other.as_any().downcast_ref::<DateTimeBox>() {
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<dyn NyashBox> {
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<dyn NyashBox> {
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<dyn NyashBox> {
Box::new(self.clone())
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_timer) = other.as_any().downcast_ref::<TimerBox>() {
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()")
}
}