Skip to content

Commit

Permalink
feat: implement inequality post processing for timestamps
Browse files Browse the repository at this point in the history
fix: add tests

fix: tests

fix: docs and tests
  • Loading branch information
Dustin-Ray committed Sep 17, 2024
1 parent f6b0fbe commit 5a68319
Show file tree
Hide file tree
Showing 4 changed files with 659 additions and 16 deletions.
55 changes: 49 additions & 6 deletions crates/proof-of-sql-parser/src/posql_time/timezone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ impl PoSQLTimeZone {
PoSQLTimeZone::FixedOffset(offset)
}
}

/// For comparisons, normalize a timestamp based on a timezone offset so
/// it can be compared to another timestamp.
pub fn normalize_to_utc(timestamp: i64, tz: &PoSQLTimeZone) -> i64 {
match tz {
PoSQLTimeZone::Utc => timestamp, // No adjustment needed
PoSQLTimeZone::FixedOffset(offset) => timestamp - *offset as i64, // Adjust by offset in seconds
}
}
}

impl TryFrom<&Option<Arc<str>>> for PoSQLTimeZone {
Expand Down Expand Up @@ -74,7 +83,7 @@ impl fmt::Display for PoSQLTimeZone {

#[cfg(test)]
mod timezone_parsing_tests {
use crate::posql_time::timezone;
use crate::posql_time::{timezone, PoSQLTimeZone, PoSQLTimestamp};

#[test]
fn test_display_fixed_offset_positive() {
Expand All @@ -93,11 +102,6 @@ mod timezone_parsing_tests {
let timezone = timezone::PoSQLTimeZone::Utc;
assert_eq!(format!("{}", timezone), "+00:00");
}
}

#[cfg(test)]
mod timezone_offset_tests {
use crate::posql_time::{timestamp::PoSQLTimestamp, timezone};

#[test]
fn test_utc_timezone() {
Expand Down Expand Up @@ -130,4 +134,43 @@ mod timezone_offset_tests {
let result = PoSQLTimestamp::try_from(input).unwrap();
assert_eq!(result.timezone(), expected_timezone);
}

#[test]
fn test_from_offset() {
// UTC case
let tz = PoSQLTimeZone::from_offset(0);
assert!(matches!(tz, PoSQLTimeZone::Utc));

// Fixed offset case
let tz = PoSQLTimeZone::from_offset(3600); // UTC+1
assert!(matches!(tz, PoSQLTimeZone::FixedOffset(3600)));

// Negative offset case (UTC-5)
let tz = PoSQLTimeZone::from_offset(-18000);
assert!(matches!(tz, PoSQLTimeZone::FixedOffset(-18000)));
}

#[test]
fn test_normalize_to_utc_with_utc() {
let timestamp = 1231006505; // Unix timestamp in seconds
let tz = PoSQLTimeZone::Utc;
let normalized = PoSQLTimeZone::normalize_to_utc(timestamp, &tz);
assert_eq!(normalized, timestamp); // No adjustment for UTC
}

#[test]
fn test_normalize_to_utc_with_positive_offset() {
let timestamp = 1231006505; // Unix timestamp in seconds
let tz = PoSQLTimeZone::FixedOffset(3600); // UTC+1 (3600 seconds offset)
let normalized = PoSQLTimeZone::normalize_to_utc(timestamp, &tz);
assert_eq!(normalized, 1231006505 - 3600); // Adjusted by 1 hour
}

#[test]
fn test_normalize_to_utc_with_negative_offset() {
let timestamp = 1231006505; // Unix timestamp in seconds
let tz = PoSQLTimeZone::FixedOffset(-18000); // UTC-5 (18000 seconds offset)
let normalized = PoSQLTimeZone::normalize_to_utc(timestamp, &tz);
assert_eq!(normalized, 1231006505 + 18000); // Adjusted by 5 hours
}
}
177 changes: 177 additions & 0 deletions crates/proof-of-sql-parser/src/posql_time/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,40 @@ pub enum PoSQLTimeUnit {
Nanosecond,
}

impl PoSQLTimeUnit {
/// Convert the numerical unit of one timeunit to another for comparison purposes.
pub fn normalize_timeunit(
timestamp: i64,
from_unit: &PoSQLTimeUnit,
to_unit: &PoSQLTimeUnit,
) -> i64 {
match (from_unit, to_unit) {
// Conversions from Seconds
(PoSQLTimeUnit::Second, PoSQLTimeUnit::Millisecond) => timestamp * 1000,
(PoSQLTimeUnit::Second, PoSQLTimeUnit::Microsecond) => timestamp * 1_000_000,
(PoSQLTimeUnit::Second, PoSQLTimeUnit::Nanosecond) => timestamp * 1_000_000_000,

// Conversions from Milliseconds
(PoSQLTimeUnit::Millisecond, PoSQLTimeUnit::Second) => timestamp / 1000,
(PoSQLTimeUnit::Millisecond, PoSQLTimeUnit::Microsecond) => timestamp * 1000,
(PoSQLTimeUnit::Millisecond, PoSQLTimeUnit::Nanosecond) => timestamp * 1_000_000,

// Conversions from Microseconds
(PoSQLTimeUnit::Microsecond, PoSQLTimeUnit::Second) => timestamp / 1_000_000,
(PoSQLTimeUnit::Microsecond, PoSQLTimeUnit::Millisecond) => timestamp / 1000,
(PoSQLTimeUnit::Microsecond, PoSQLTimeUnit::Nanosecond) => timestamp * 1000,

// Conversions from Nanoseconds
(PoSQLTimeUnit::Nanosecond, PoSQLTimeUnit::Second) => timestamp / 1_000_000_000,
(PoSQLTimeUnit::Nanosecond, PoSQLTimeUnit::Millisecond) => timestamp / 1_000_000,
(PoSQLTimeUnit::Nanosecond, PoSQLTimeUnit::Microsecond) => timestamp / 1000,

// If units are the same, no adjustment is needed
_ => timestamp,
}
}
}

impl TryFrom<&str> for PoSQLTimeUnit {
type Error = PoSQLTimestampError;
fn try_from(value: &str) -> Result<Self, PoSQLTimestampError> {
Expand Down Expand Up @@ -104,4 +138,147 @@ mod time_unit_tests {
expected.timestamp_nanos_opt().unwrap()
);
}
#[test]
fn test_normalize_timeunit_seconds_to_milliseconds() {
let timestamp = 1231006505; // seconds
let result = PoSQLTimeUnit::normalize_timeunit(
timestamp,
&PoSQLTimeUnit::Second,
&PoSQLTimeUnit::Millisecond,
);
assert_eq!(result, 1231006505000); // converted to milliseconds
}

#[test]
fn test_normalize_timeunit_seconds_to_microseconds() {
let timestamp = 1231006505; // seconds
let result = PoSQLTimeUnit::normalize_timeunit(
timestamp,
&PoSQLTimeUnit::Second,
&PoSQLTimeUnit::Microsecond,
);
assert_eq!(result, 1231006505000000); // converted to microseconds
}

#[test]
fn test_normalize_timeunit_seconds_to_nanoseconds() {
let timestamp = 1231006505; // seconds
let result = PoSQLTimeUnit::normalize_timeunit(
timestamp,
&PoSQLTimeUnit::Second,
&PoSQLTimeUnit::Nanosecond,
);
assert_eq!(result, 1231006505000000000); // converted to nanoseconds
}

#[test]
fn test_normalize_timeunit_milliseconds_to_seconds() {
let timestamp = 1231006505000; // milliseconds
let result = PoSQLTimeUnit::normalize_timeunit(
timestamp,
&PoSQLTimeUnit::Millisecond,
&PoSQLTimeUnit::Second,
);
assert_eq!(result, 1231006505); // converted to seconds
}

#[test]
fn test_normalize_timeunit_milliseconds_to_microseconds() {
let timestamp = 1231006505; // milliseconds
let result = PoSQLTimeUnit::normalize_timeunit(
timestamp,
&PoSQLTimeUnit::Millisecond,
&PoSQLTimeUnit::Microsecond,
);
assert_eq!(result, 1231006505000); // converted to microseconds
}

#[test]
fn test_normalize_timeunit_milliseconds_to_nanoseconds() {
let timestamp = 1231006505; // milliseconds
let result = PoSQLTimeUnit::normalize_timeunit(
timestamp,
&PoSQLTimeUnit::Millisecond,
&PoSQLTimeUnit::Nanosecond,
);
assert_eq!(result, 1231006505000000); // converted to nanoseconds
}

#[test]
fn test_normalize_timeunit_microseconds_to_seconds() {
let timestamp = 1231006505000000; // microseconds
let result = PoSQLTimeUnit::normalize_timeunit(
timestamp,
&PoSQLTimeUnit::Microsecond,
&PoSQLTimeUnit::Second,
);
assert_eq!(result, 1231006505); // converted to seconds
}

#[test]
fn test_normalize_timeunit_microseconds_to_milliseconds() {
let timestamp = 1231006505000; // microseconds
let result = PoSQLTimeUnit::normalize_timeunit(
timestamp,
&PoSQLTimeUnit::Microsecond,
&PoSQLTimeUnit::Millisecond,
);
assert_eq!(result, 1231006505); // converted to milliseconds
}

#[test]
fn test_normalize_timeunit_microseconds_to_nanoseconds() {
let timestamp = 1231006505; // microseconds
let result = PoSQLTimeUnit::normalize_timeunit(
timestamp,
&PoSQLTimeUnit::Microsecond,
&PoSQLTimeUnit::Nanosecond,
);
assert_eq!(result, 1231006505000); // converted to nanoseconds
}

#[test]
fn test_normalize_timeunit_nanoseconds_to_seconds() {
let timestamp = 1231006505000000000; // nanoseconds
let result = PoSQLTimeUnit::normalize_timeunit(
timestamp,
&PoSQLTimeUnit::Nanosecond,
&PoSQLTimeUnit::Second,
);
assert_eq!(result, 1231006505); // converted to seconds
}

#[test]
fn test_normalize_timeunit_nanoseconds_to_milliseconds() {
let timestamp = 1231006505000000; // nanoseconds
let result = PoSQLTimeUnit::normalize_timeunit(
timestamp,
&PoSQLTimeUnit::Nanosecond,
&PoSQLTimeUnit::Millisecond,
);
assert_eq!(result, 1231006505); // converted to milliseconds
}

#[test]
fn test_normalize_timeunit_nanoseconds_to_microseconds() {
let timestamp = 1231006505000; // nanoseconds
let result = PoSQLTimeUnit::normalize_timeunit(
timestamp,
&PoSQLTimeUnit::Nanosecond,
&PoSQLTimeUnit::Microsecond,
);
assert_eq!(result, 1231006505); // converted to microseconds
}

#[test]
fn test_normalize_timeunit_same_units() {
// If from_unit and to_unit are the same, it should return the timestamp as is
let timestamp = 1231006505;
let result = PoSQLTimeUnit::normalize_timeunit(
timestamp,
&PoSQLTimeUnit::Second,
&PoSQLTimeUnit::Second,
);
assert_eq!(result, timestamp); // No conversion needed
}
}
Loading

0 comments on commit 5a68319

Please sign in to comment.