Truncate microseconds since epoch to the specified precision
(field: &str, timestamp: i64)
| 432 | |
| 433 | /// Truncate microseconds since epoch to the specified precision |
| 434 | fn truncate_date(field: &str, timestamp: i64) -> Result<i64> { |
| 435 | let secs = timestamp / 1_000_000; |
| 436 | let micros = timestamp % 1_000_000; |
| 437 | let nanos = (micros * 1000) as u32; |
| 438 | |
| 439 | let datetime = DateTime::from_timestamp(secs, nanos) |
| 440 | .ok_or_else(|| Error::UserFunctionError("Invalid timestamp".into()))?; |
| 441 | |
| 442 | let truncated = match field.to_lowercase().as_str() { |
| 443 | "microseconds" => { |
| 444 | // Already at microsecond precision |
| 445 | timestamp |
| 446 | } |
| 447 | "milliseconds" => { |
| 448 | // Truncate to millisecond |
| 449 | (timestamp / 1000) * 1000 |
| 450 | } |
| 451 | "second" => (timestamp / 1_000_000) * 1_000_000, |
| 452 | "minute" => { |
| 453 | let dt = datetime.date_naive().and_hms_opt(datetime.hour(), datetime.minute(), 0).unwrap(); |
| 454 | dt.and_utc().timestamp() * 1_000_000 |
| 455 | } |
| 456 | "hour" => { |
| 457 | let dt = datetime.date_naive().and_hms_opt(datetime.hour(), 0, 0).unwrap(); |
| 458 | dt.and_utc().timestamp() * 1_000_000 |
| 459 | } |
| 460 | "day" => { |
| 461 | let dt = datetime.date_naive().and_hms_opt(0, 0, 0).unwrap(); |
| 462 | dt.and_utc().timestamp() * 1_000_000 |
| 463 | } |
| 464 | "week" => { |
| 465 | // Truncate to start of week (Monday) |
| 466 | let days_from_monday = datetime.weekday().num_days_from_monday(); |
| 467 | let start_of_week = datetime.date_naive() - chrono::Duration::days(days_from_monday as i64); |
| 468 | let dt = start_of_week.and_hms_opt(0, 0, 0).unwrap(); |
| 469 | dt.and_utc().timestamp() * 1_000_000 |
| 470 | } |
| 471 | "month" => { |
| 472 | let dt = NaiveDate::from_ymd_opt(datetime.year(), datetime.month(), 1) |
| 473 | .unwrap() |
| 474 | .and_hms_opt(0, 0, 0) |
| 475 | .unwrap(); |
| 476 | dt.and_utc().timestamp() * 1_000_000 |
| 477 | } |
| 478 | "quarter" => { |
| 479 | let quarter_month = ((datetime.month() - 1) / 3) * 3 + 1; |
| 480 | let dt = NaiveDate::from_ymd_opt(datetime.year(), quarter_month, 1) |
| 481 | .unwrap() |
| 482 | .and_hms_opt(0, 0, 0) |
| 483 | .unwrap(); |
| 484 | dt.and_utc().timestamp() * 1_000_000 |
| 485 | } |
| 486 | "year" => { |
| 487 | let dt = NaiveDate::from_ymd_opt(datetime.year(), 1, 1) |
| 488 | .unwrap() |
| 489 | .and_hms_opt(0, 0, 0) |
| 490 | .unwrap(); |
| 491 | dt.and_utc().timestamp() * 1_000_000 |
no outgoing calls
no test coverage detected