aboutsummaryrefslogtreecommitdiff
path: root/examples/time
diff options
context:
space:
mode:
Diffstat (limited to 'examples/time')
-rw-r--r--examples/time/README.md5
-rw-r--r--examples/time/time.tm210
-rw-r--r--examples/time/time_defs.h30
3 files changed, 0 insertions, 245 deletions
diff --git a/examples/time/README.md b/examples/time/README.md
deleted file mode 100644
index 55f725f1..00000000
--- a/examples/time/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Time
-
-This is a Tomo library for working with dates and times. The `Time` type that
-is provided is a date-and-time datatype that refers to a specific moment in
-time.
diff --git a/examples/time/time.tm b/examples/time/time.tm
deleted file mode 100644
index 1796654d..00000000
--- a/examples/time/time.tm
+++ /dev/null
@@ -1,210 +0,0 @@
-# Time - a module for dealing with dates and times
-use ./time_defs.h
-
-enum Weekday(Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday)
-
-struct TimeInfo(year,month,day,hour,minute,second,nanosecond:Int, weekday:Weekday, day_of_year:Int, timezone:Text)
-
-struct Time(tv_sec:Int64, tv_usec:Int64; extern)
- func now(->Time)
- return C_code : Time (
- struct timespec ts;
- if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
- fail("Couldn't get the time!");
- (Time){.tv_sec=ts.tv_sec, .tv_usec=ts.tv_nsec/1000}
- )
-
- func local_timezone(->Text)
- C_code {
- if (_local_timezone.length < 0) {
- static char buf[PATH_MAX];
- ssize_t len = readlink("/etc/localtime", buf, sizeof(buf));
- if (len < 0)
- fail("Could not get local tz!");
-
- char *zoneinfo = strstr(buf, "/zoneinfo/");
- if (zoneinfo)
- _local_timezone = Text$from_str(zoneinfo + strlen("/zoneinfo/"));
- else
- fail("Could not resolve local tz!");
- }
- }
- return C_code:Text(_local_timezone)
-
- func set_local_timezone(timezone:Text)
- C_code {
- setenv("TZ", @(CString(timezone)), 1);
- _local_timezone = @timezone;
- tzset();
- }
-
- func format(t:Time, format="%c", timezone=Time.local_timezone() -> Text)
- return C_code : Text (
- struct tm result;
- time_t time = @t.tv_sec;
- struct tm *final_info;
- WITH_TIMEZONE(@timezone, final_info = localtime_r(&time, &result));
- static char buf[256];
- size_t len = strftime(buf, sizeof(buf), String(@format), final_info);
- Text$from_strn(buf, len)
- )
-
- func new(year,month,day:Int, hour=0, minute=0, second=0.0, timezone=Time.local_timezone() -> Time)
- return C_code : Time(
- struct tm info = {
- .tm_min=Int32$from_int(@minute, false),
- .tm_hour=Int32$from_int(@hour, false),
- .tm_mday=Int32$from_int(@day, false),
- .tm_mon=Int32$from_int(@month, false) - 1,
- .tm_year=Int32$from_int(@year, false) - 1900,
- .tm_isdst=-1,
- };
-
- time_t t;
- WITH_TIMEZONE(@timezone, t = mktime(&info));
- (Time){.tv_sec=t + (time_t)@second, .tv_usec=(suseconds_t)(fmod(@second, 1.0) * 1e9)}
- )
-
- func unix_timestamp(t:Time -> Int64)
- return C_code:Int64((int64_t)@t.tv_sec)
-
- func from_unix_timestamp(timestamp:Int64 -> Time)
- return C_code:Time((Time){.tv_sec=@timestamp};)
-
- func seconds_till(t:Time, target:Time -> Num)
- seconds := Num(target.tv_sec - t.tv_sec)
- seconds += 1e-9*Num(target.tv_usec - t.tv_usec)
- return seconds
-
- func minutes_till(t:Time, target:Time -> Num)
- return t.seconds_till(target)/60.
-
- func hours_till(t:Time, target:Time -> Num)
- return t.seconds_till(target)/3600.
-
- func relative(t:Time, relative_to=Time.now(), timezone=Time.local_timezone() -> Text)
- C_code {
- struct tm info = {};
- struct tm relative_info = {};
- WITH_TIMEZONE(@timezone, {
- localtime_r(&@t.tv_sec, &info);
- localtime_r(&@relative_to.tv_sec, &relative_info);
- });
- double second_diff = @(relative_to.seconds_till(t));
- if (info.tm_year != relative_info.tm_year && fabs(second_diff) > 365.*24.*60.*60.)
- return num_format((long)info.tm_year - (long)relative_info.tm_year, "year");
- else if (info.tm_mon != relative_info.tm_mon && fabs(second_diff) > 31.*24.*60.*60.)
- return num_format(12*((long)info.tm_year - (long)relative_info.tm_year) + (long)info.tm_mon - (long)relative_info.tm_mon, "month");
- else if (info.tm_yday != relative_info.tm_yday && fabs(second_diff) > 24.*60.*60.)
- return num_format(round(second_diff/(24.*60.*60.)), "day");
- else if (info.tm_hour != relative_info.tm_hour && fabs(second_diff) > 60.*60.)
- return num_format(round(second_diff/(60.*60.)), "hour");
- else if (info.tm_min != relative_info.tm_min && fabs(second_diff) > 60.)
- return num_format(round(second_diff/(60.)), "minute");
- else {
- if (fabs(second_diff) < 1e-6)
- return num_format((long)(second_diff*1e9), "nanosecond");
- else if (fabs(second_diff) < 1e-3)
- return num_format((long)(second_diff*1e6), "microsecond");
- else if (fabs(second_diff) < 1.0)
- return num_format((long)(second_diff*1e3), "millisecond");
- else
- return num_format((long)(second_diff), "second");
- }
- }
- fail("Unreachable")
-
- func time(t:Time, seconds=no, am_pm=yes, timezone=Time.local_timezone() -> Text)
- time := if seconds and am_pm
- t.format("%l:%M:%S%P")
- else if seconds and not am_pm
- t.format("%T")
- else if not seconds and am_pm
- t.format("%l:%M%P")
- else
- t.format("%H:%M")
- return time.trim()
-
- func date(t:Time, timezone=Time.local_timezone() -> Text)
- return t.format("%F")
-
- func info(t:Time, timezone=Time.local_timezone() -> TimeInfo)
- return C_code : TimeInfo (
- struct tm info = {};
- WITH_TIMEZONE(@timezone, localtime_r(&@t.tv_sec, &info));
- (_$time$TimeInfo$$type){
- .year = I(info.tm_year + 1900),
- .month = I(info.tm_mon + 1),
- .day = I(info.tm_mday),
- .hour = I(info.tm_hour),
- .minute = I(info.tm_min),
- .second = I(info.tm_sec),
- .nanosecond = I(@t.tv_usec),
- .weekday = (_$time$Weekday$$type){.$tag=info.tm_wday + 1},
- .day_of_year = I(info.tm_yday),
- .timezone = @timezone,
- }
- )
-
- func after(t:Time, seconds=0.0, minutes=0.0, hours=0.0, days=0, weeks=0, months=0, years=0, timezone=Time.local_timezone() -> Time)
- return C_code : Time (
- double offset = @seconds + 60.*@minutes + 3600.*@hours ;
- @t.tv_sec += (time_t)offset;
-
- struct tm info = {};
- WITH_TIMEZONE(@timezone, localtime_r(&@t.tv_sec, &info));
-
- info.tm_mday += Int32$from_int(@days, false) + 7*Int32$from_int(@weeks, false);
- info.tm_mon += Int32$from_int(@months, false);
- info.tm_year += Int32$from_int(@years, false);
-
- time_t t = mktime(&info);
- (Time){
- .tv_sec=t,
- .tv_usec=@t.tv_usec + (suseconds_t)(fmod(offset, 1.0) * 1e9),
- }
- )
-
- func parse(text:Text, format="%Y-%m-%dT%H:%M:%S%z", timezone=Time.local_timezone() -> Time?)
- return C_code : Time? (
- struct tm info = {.tm_isdst=-1};
- const char *str = Text$as_c_string(@text);
- const char *fmt = Text$as_c_string(@format);
- if (strstr(fmt, "%Z"))
- fail("The %Z specifier is not supported for time parsing!");
-
- char *invalid;
- WITH_TIMEZONE(@timezone, invalid = strptime(str, fmt, &info));
- if (!invalid || invalid[0] != '\0')
- return (_$time$$OptionalTime$$type){.is_none=true};
-
- long offset = info.tm_gmtoff; // Need to cache this because mktime() mutates it to local tz >:(
- time_t t;
- WITH_TIMEZONE(@timezone, t = mktime(&info));
- (_$time$$OptionalTime$$type){.value={.tv_sec=t + offset - info.tm_gmtoff}};
- )
-
-func _run_tests()
- >> Time.now().format()
- >> Time.set_local_timezone("Europe/Paris")
- >> Time.now().format()
- >> Time.set_local_timezone("America/New_York")
- >> Time.now().format()
- # >> Time.now().format(timezone="Europe/Paris")
- # >> Time.now().format()
- # >> Time.now().format("%Y-%m-%d")
- # >> Time.new(2023, 11, 5).format()
- # >> Time.local_timezone()
-
- # >> Time.new(2023, 11, 5).seconds_till(Time.now())
- # >> Time.new(2023, 11, 5).relative()
-
- # >> Time.now().info()
- # >> Time.now().time()
- # >> Time.now().date()
-
- # >> Time.parse("2023-11-05 01:01", "%Y-%m-%d %H:%M")
- # >> Time.parse("2023-11-05 01:01", "%Y-%m-%d %H:%M", timezone="Europe/Paris")
-
-func main()
- _run_tests()
diff --git a/examples/time/time_defs.h b/examples/time/time_defs.h
deleted file mode 100644
index fd8fd4f3..00000000
--- a/examples/time/time_defs.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#pragma once
-#include <time.h>
-#include <sys/time.h>
-
-typedef struct timeval Time;
-
-static OptionalText_t _local_timezone = NONE_TEXT;
-
-static INLINE Text_t num_format(long n, const char *unit)
-{
- if (n == 0)
- return Text("now");
- return Text$format((n == 1 || n == -1) ? "%ld %s %s" : "%ld %ss %s", n < 0 ? -n : n, unit, n < 0 ? "ago" : "later");
-}
-
-static void set_local_timezone(Text_t tz)
-{
- setenv("TZ", Text$as_c_string(tz), 1);
- _local_timezone = tz;
- tzset();
-}
-
-#define WITH_TIMEZONE(tz, body) ({ if (tz.length >= 0) { \
- OptionalText_t old_timezone = _local_timezone; \
- set_local_timezone(tz); \
- body; \
- set_local_timezone(old_timezone); \
- } else { \
- body; \
- }})