sklears_preprocessing/temporal/
datetime_utils.rs

1//! DateTime utilities and date/time component extraction
2//!
3//! This module provides utilities for working with timestamps and extracting
4//! various date and time components for temporal feature engineering.
5
6use sklears_core::types::Float;
7
8/// Simple DateTime structure for working with Unix timestamps
9#[derive(Debug, Clone, Copy)]
10pub struct DateTime {
11    /// Unix timestamp in seconds since epoch
12    pub timestamp: i64,
13}
14
15impl DateTime {
16    /// Create a new DateTime from Unix timestamp
17    pub fn from_timestamp(timestamp: i64) -> Self {
18        Self { timestamp }
19    }
20
21    /// Convert timestamp to date components assuming UTC
22    /// This is a simplified implementation - in practice you'd use a proper datetime library
23    pub fn to_components(&self, timezone_offset: Option<Float>) -> DateComponents {
24        let mut timestamp = self.timestamp;
25
26        // Apply timezone offset if provided
27        if let Some(offset) = timezone_offset {
28            timestamp += (offset * 3600.0) as i64;
29        }
30
31        // Simplified calculation - assumes Gregorian calendar
32        let days_since_epoch = timestamp / 86400;
33        let seconds_in_day = timestamp % 86400;
34
35        // Calculate year (simplified)
36        let mut year = 1970;
37        let mut remaining_days = days_since_epoch;
38
39        // This is a very simplified year calculation
40        while remaining_days >= 365 {
41            let days_in_year = if Self::is_leap_year(year) { 366 } else { 365 };
42            if remaining_days >= days_in_year {
43                remaining_days -= days_in_year;
44                year += 1;
45            } else {
46                break;
47            }
48        }
49
50        // Calculate month and day (simplified)
51        let days_in_months = if Self::is_leap_year(year) {
52            [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
53        } else {
54            [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
55        };
56
57        let mut month = 1;
58        let mut day_of_month = remaining_days + 1;
59
60        for &days_in_month in &days_in_months {
61            if day_of_month > days_in_month {
62                day_of_month -= days_in_month;
63                month += 1;
64            } else {
65                break;
66            }
67        }
68
69        // Calculate time components
70        let hour = (seconds_in_day / 3600) as u8;
71        let minute = ((seconds_in_day % 3600) / 60) as u8;
72        let second = (seconds_in_day % 60) as u8;
73
74        // Calculate additional components
75        let day_of_week = ((days_since_epoch + 4) % 7) as u8; // Jan 1, 1970 was Thursday (4)
76        let quarter = ((month - 1) / 3 + 1) as u8;
77        let day_of_year = Self::calculate_day_of_year(year, month as u8, day_of_month as u8);
78        let week_of_year = Self::calculate_week_of_year(year, month as u8, day_of_month as u8);
79
80        DateComponents {
81            year: year as u32,
82            month: month as u8,
83            day: day_of_month as u8,
84            hour,
85            minute,
86            second,
87            day_of_week,
88            quarter,
89            day_of_year,
90            week_of_year,
91        }
92    }
93
94    fn is_leap_year(year: i64) -> bool {
95        (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
96    }
97
98    fn calculate_day_of_year(year: i64, month: u8, day: u8) -> u16 {
99        let days_in_months = if Self::is_leap_year(year) {
100            [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
101        } else {
102            [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
103        };
104
105        let mut day_of_year = day as u16;
106        for i in 0..(month - 1) {
107            day_of_year += days_in_months[i as usize] as u16;
108        }
109        day_of_year
110    }
111
112    fn calculate_week_of_year(year: i64, month: u8, day: u8) -> u8 {
113        let day_of_year = Self::calculate_day_of_year(year, month, day);
114        // Simplified week calculation (assumes week starts on Monday)
115        ((day_of_year - 1) / 7 + 1) as u8
116    }
117}
118
119/// Date and time components
120#[derive(Debug, Clone, Copy)]
121pub struct DateComponents {
122    pub year: u32,
123    pub month: u8,        // 1-12
124    pub day: u8,          // 1-31
125    pub hour: u8,         // 0-23
126    pub minute: u8,       // 0-59
127    pub second: u8,       // 0-59
128    pub day_of_week: u8,  // 0-6 (Monday-Sunday)
129    pub quarter: u8,      // 1-4
130    pub day_of_year: u16, // 1-366
131    pub week_of_year: u8, // 1-53
132}