Functional Weave
Code in Python

time.iso-to-unix@1.0.0

impl/rust.rs

2,266 bytes · the Rust implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::dates_add_days::epoch_day_from_iso;  ← from dates.add-days ^1.0.0 · built alongside by fune

fn num(b: &[u8], from: usize, to: usize) -> i64 {
    b[from..to].iter().fold(0, |n, d| n * 10 + i64::from(d - b'0'))
}

/// An RFC 3339 date-time to Unix seconds, parsed by position.
///
/// # Panics
/// Panics on anything that is not an RFC 3339 date-time with a zone, or on
/// a date that does not exist.
pub fn iso_to_unix(timestamp: &str) -> i64 {
    let bad = || -> ! {
        panic!(
            "\"{}\" is not an RFC 3339 timestamp such as 2026-09-26T12:00:00Z",
            timestamp
        )
    };
    // Bytes: every accepted character is ASCII, so a multi-byte character
    // fails a check wherever it sits, as it does in the other languages.
    let t = timestamp.as_bytes();
    if t.len() < 20 {
        bad();
    }
    for i in [0, 1, 2, 3, 5, 6, 8, 9, 11, 12, 14, 15, 17, 18] {
        if !t[i].is_ascii_digit() {
            bad();
        }
    }
    if t[4] != b'-' || t[7] != b'-' || (t[10] != b'T' && t[10] != b't') || t[13] != b':' || t[16] != b':' {
        bad();
    }
    let mut i = 19;
    if t[i] == b'.' {
        i += 1;
        let start = i;
        while i < t.len() && t[i].is_ascii_digit() {
            i += 1;
        }
        if i == start {
            bad();
        }
    }
    let offset: i64;
    if i < t.len() && (t[i] == b'Z' || t[i] == b'z') && i + 1 == t.len() {
        offset = 0;
    } else if i < t.len()
        && (t[i] == b'+' || t[i] == b'-')
        && i + 6 == t.len()
        && t[i + 1].is_ascii_digit()
        && t[i + 2].is_ascii_digit()
        && t[i + 3] == b':'
        && t[i + 4].is_ascii_digit()
        && t[i + 5].is_ascii_digit()
    {
        let oh = num(t, i + 1, i + 3);
        let om = num(t, i + 4, i + 6);
        if oh > 23 || om > 59 {
            bad();
        }
        offset = if t[i] == b'+' { 1 } else { -1 } * (oh * 3600 + om * 60);
    } else {
        bad();
    }
    let h = num(t, 11, 13);
    let m = num(t, 14, 16);
    let s = num(t, 17, 19);
    if h > 23 || m > 59 || s > 59 {
        bad();
    }
    epoch_day_from_iso(&timestamp[0..10]) * 86400 + h * 3600 + m * 60 + s - offset
}

pub fn fune_vector(args: &[Value]) -> Value {
    Value::Int(iso_to_unix(args[0].as_str()))
}