common: Add the time module.
authorTilman Sauerbeck <tilman@code-monkey.de>
Thu, 2 Jan 2020 12:28:59 +0000 (13:28 +0100)
committerTilman Sauerbeck <tilman@code-monkey.de>
Mon, 6 Jan 2020 09:45:34 +0000 (10:45 +0100)
This currently only contains the equivalent of gmtime(), which was
adapted from Rich Felker's musl.

SConscript.libcommon
src/common/lib.rs
src/common/time.rs [new file with mode: 0644]

index d4a3c2c611bcb3c9be132985feb349dde26718cb..4e5b06516785ae37b23901174d6f088794c47522 100644 (file)
@@ -20,6 +20,7 @@ source_files_rs = [
     'src/common/screen.rs',
     'src/common/gps.rs',
     'src/common/fmt.rs',
+    'src/common/time.rs',
 ]
 
 source_files_c = [
index dcca2f2f7f7c319094c77ce78809393a7ef5bc66..e38ff52cf453971e4da618256bf09d7a8e2262ed 100644 (file)
@@ -42,6 +42,7 @@ pub mod screen;
 pub mod display;
 pub mod gps;
 pub mod fmt;
+pub mod time;
 
 use core::panic::PanicInfo;
 
diff --git a/src/common/time.rs b/src/common/time.rs
new file mode 100644 (file)
index 0000000..0413c58
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2020 Tilman Sauerbeck (tilman at code-monkey de)
+ *
+ * Time::from_unix_time() adapted from musl's __secs_to_tm() which is
+ * Copyright © 2005-2020 Rich Felker, et al.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+pub struct Time {
+    seconds: i32,
+    minutes: i32,
+    hours: i32,
+    day: i32,
+    month: i32,
+    year: i32,
+}
+
+// 2000-03-01 (mod 400 year, immediately after feb29
+const LEAPOCH: i32 = (946684800 + 86400 * (31 + 29));
+
+const DAYS_PER_400Y: i32 = (365 * 400 + 97);
+const DAYS_PER_100Y: i32 = (365 * 100 + 24);
+const DAYS_PER_4Y  : i32 = (365 *   4 +  1);
+
+const DAYS_IN_MONTH : [i32; 12] = [ 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29 ];
+
+impl Time {
+    pub fn from_unix_time(u: u32) -> Option<Time> {
+        let t = u as i32;
+
+        let secs = t - LEAPOCH;
+        let mut days = secs / 86400;
+        let mut remsecs = secs % 86400;
+
+        if remsecs < 0 {
+            remsecs += 86400;
+            days -= 1;
+        }
+
+        let mut qc_cycles = days / DAYS_PER_400Y;
+        let mut remdays = days % DAYS_PER_400Y;
+
+        if remdays < 0 {
+            remdays += DAYS_PER_400Y;
+            qc_cycles -= 1;
+        }
+
+        let mut c_cycles = remdays / DAYS_PER_100Y;
+
+        if c_cycles == 4 {
+            c_cycles -= 1;
+        }
+
+        remdays -= c_cycles * DAYS_PER_100Y;
+
+        let mut q_cycles = remdays / DAYS_PER_4Y;
+
+        if q_cycles == 25 {
+            q_cycles -= 1;
+        }
+
+        remdays -= q_cycles * DAYS_PER_4Y;
+
+        let mut remyears = remdays / 365;
+
+        if remyears == 4 {
+            remyears -= 1;
+        }
+
+        remdays -= remyears * 365;
+
+        let mut years =
+            remyears + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles;
+
+        let mut months = 0;
+
+        while remdays >= DAYS_IN_MONTH[months as usize] {
+            remdays -= DAYS_IN_MONTH[months as usize];
+            months += 1;
+        }
+
+        if months >= 10 {
+            months -= 12;
+            years += 1;
+        }
+
+        if years + 100 > i32::max_value() || years + 100 < i32::min_value() {
+            None
+        } else {
+            Some(Time {
+                year: years + 100,
+                month: months + 2,
+                day: remdays + 1,
+                hours: remsecs / 3600,
+                minutes: remsecs / 60 % 60,
+                seconds: remsecs % 60,
+            })
+        }
+    }
+}