diff --git a/CMakeLists.txt b/CMakeLists.txt index 3240d35..7bc6100 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(fun VERSION 0.36.0 LANGUAGES C) +project(fun VERSION 0.36.1 LANGUAGES C) set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) diff --git a/examples/datetime_extended.fun b/examples/datetime_extended.fun new file mode 100644 index 0000000..baf9cc9 --- /dev/null +++ b/examples/datetime_extended.fun @@ -0,0 +1,66 @@ +#!/usr/bin/env fun + +/* + * This file is part of the Fun programming language. + * https://fun-lang.xyz/ + * + * Copyright 2025 Johannes Findeisen + * Licensed under the terms of the Apache-2.0 license. + * https://opensource.org/license/apache-2-0 + * + * Added: 2025-12-09 + */ + +// Extended Date/Time examples using the stdlib DateTime class +#include + +fun main() + dt = DateTime() + + print("--- Basics ---") + now_ms = dt.now_ms() + print(join(["now_ms: ", to_string(now_ms)], "")) + print(join(["now_s: ", to_string(dt.now_s())], "")) + print(join(["iso_now: ", dt.iso_now()], "")) + print(join(["today: ", dt.today_str()], "")) + + print("--- Formatting helpers ---") + print(join(["iso_from(now): ", dt.iso_from(now_ms)], "")) + print(join(["date_str(now): ", dt.date_str(now_ms)], "")) + print(join(["time_str(now): ", dt.time_str(now_ms)], "")) + + print("--- Conversions ---") + print(join(["ms_to_s(1234): ", to_string(dt.ms_to_s(1234))], "")) + print(join(["s_to_ms(2): ", to_string(dt.s_to_ms(2))], "")) + + print("--- Arithmetic ---") + in_2s = dt.add_seconds(now_ms, 2) + print(join(["in 2s (ms): ", to_string(in_2s)], "")) + print(join(["diff_ms(now, in_2s): ", to_string(dt.diff_ms(now_ms, in_2s))], "")) + + print("--- Timer ---") + t0 = dt.start_timer() + dt.sleep_ms(120) + print(join(["elapsed ~120ms: ", to_string(dt.elapsed_ms(t0)), " ms"], "")) + +main() + +/* Possible output: +--- Basics --- +now_ms: 1765320472780 +now_s: 1765320472 +iso_now: 2025-12-09T23:47:52 +today: 2025-12-09 +--- Formatting helpers --- +iso_from(now): 2025-12-09T23:47:52 +date_str(now): 2025-12-09 +time_str(now): 23:47:52 +--- Conversions --- +ms_to_s(1234): 1 +s_to_ms(2): 2000 +--- Arithmetic --- +in 2s (ms): 1765320474780 +diff_ms(now, in_2s): 2000 +--- Timer --- +elapsed ~120ms: 120 ms +*/ diff --git a/examples/datetime_timer.fun b/examples/datetime_timer.fun new file mode 100644 index 0000000..be1d21c --- /dev/null +++ b/examples/datetime_timer.fun @@ -0,0 +1,31 @@ +#!/usr/bin/env fun + +/* + * This file is part of the Fun programming language. + * https://fun-lang.xyz/ + * + * Copyright 2025 Johannes Findeisen + * Licensed under the terms of the Apache-2.0 license. + * https://opensource.org/license/apache-2-0 + * + * Added: 2025-12-09 + */ + +// Simple stopwatch using DateTime helpers +#include + +fun main() + dt = DateTime() + print("Starting timer for ~250ms ...") + t0 = dt.start_timer() + dt.sleep_s(0.2) // 200 ms + dt.sleep_ms(50) + elapsed = dt.elapsed_ms(t0) + print(join(["Elapsed: ", to_string(elapsed), " ms"], "")) + +main() + +/* Possible output: +Starting timer for ~250ms ... +Elapsed: 250 ms +*/ diff --git a/examples/tk_hello.fun b/examples/tk_hello.fun old mode 100644 new mode 100755 diff --git a/lib/utils/datetime.fun b/lib/utils/datetime.fun index 38517ca..0db8130 100644 --- a/lib/utils/datetime.fun +++ b/lib/utils/datetime.fun @@ -1,3 +1,12 @@ +/* + * This file is part of the Fun programming language. + * https://fun-lang.xyz/ + * + * Copyright 2025 Johannes Findeisen + * Licensed under the terms of the Apache-2.0 license. + * https://opensource.org/license/apache-2-0 + */ + // Date/time utilities abstraction for the Fun stdlib. // Minimal version to validate syntax. @@ -30,3 +39,66 @@ class DateTime() fun iso_now(this) ms = time_now_ms() return date_format(ms, "%Y-%m-%dT%H:%M:%S") + + // Seconds since Unix epoch (integer) + fun now_s(this) + return to_number(time_now_ms() / 1000) + + // Convert milliseconds to seconds (floor) + fun ms_to_s(this, ms) + return to_number(to_number(ms) / 1000) + + // Convert seconds to milliseconds + fun s_to_ms(this, s) + return to_number(to_number(s) * 1000) + + // Add milliseconds to an epoch-ms timestamp + fun add_ms(this, ms, delta_ms) + return to_number(to_number(ms) + to_number(delta_ms)) + + // Add seconds to an epoch-ms timestamp + fun add_seconds(this, ms, seconds) + return this.add_ms(ms, this.s_to_ms(seconds)) + + // Difference in milliseconds: b - a + fun diff_ms(this, a_ms, b_ms) + return to_number(to_number(b_ms) - to_number(a_ms)) + + // Milliseconds elapsed since given epoch-ms timestamp + fun since_ms(this, past_ms) + return this.diff_ms(past_ms, this.now_ms()) + + // Format an arbitrary epoch-ms timestamp as ISO local + fun iso_from(this, ms) + return date_format(to_number(ms), "%Y-%m-%dT%H:%M:%S") + + // Date-only string for a timestamp (YYYY-MM-DD) + fun date_str(this, ms) + return date_format(to_number(ms), "%Y-%m-%d") + + // Time-only string for a timestamp (HH:MM:SS) + fun time_str(this, ms) + return date_format(to_number(ms), "%H:%M:%S") + + // Today's date as YYYY-MM-DD + fun today_str(this) + return this.date_str(this.now_ms()) + + // Start a monotonic timer + fun start_timer(this) + return clock_mono_ms() + + // Elapsed ms from a monotonic start value + fun elapsed_ms(this, start_mono_ms) + return to_number(clock_mono_ms() - to_number(start_mono_ms)) + + // Sleep for the given milliseconds (non-negative) + fun sleep_ms(this, ms) + m = to_number(ms) + if m > 0 + sleep(m) + return m + + // Sleep for the given seconds + fun sleep_s(this, s) + return this.sleep_ms(this.s_to_ms(s))